feat(capability): 转码能力包(vendor 纯 Go AMR-NB 解码器 + 黄金向量逐样本对照 + 8 哨兵 + 注册面)
This commit is contained in:
1 parent
89715d1813
commit
4a2d276881
100 files changed
+11319
No files matched your search
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or Derivative
|
||||
Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and do
|
||||
not modify the License. You may add Your own attribution notices
|
||||
within Derivative Works that You distribute, alongside or as an
|
||||
addendum to the NOTICE text from the Work, provided that such
|
||||
additional attribution notices cannot be construed as modifying
|
||||
the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -0,0 +1,15 @@
|
||||
goamr-nb
|
||||
Copyright 2026 The goamr-nb authors
|
||||
|
||||
This product is a pure-Go port of AMR-NB (3GPP TS 26.071, 26.073, 26.090,
|
||||
26.101, 26.104) derived from the following Apache-2.0 licensed C reference:
|
||||
|
||||
- opencore-amrnb (AMR-NB encoder and decoder)
|
||||
https://sourceforge.net/projects/opencore-amr/
|
||||
Copyright (C) 2009 Martin Storsjo
|
||||
Copyright (C) The Android Open Source Project
|
||||
|
||||
The fixed-point DSP was translated function-by-function from the above
|
||||
source, preserving its algorithms and bit-exact semantics. The original
|
||||
work is licensed under the Apache License, Version 2.0; this port is
|
||||
distributed under the same license (see LICENSE).
|
||||
@@ -0,0 +1,51 @@
|
||||
# vendored: github.com/VoiceBlender/goamr-nb v1.0.0(AMR-NB 编解码器)
|
||||
|
||||
本目录是**第三方源码的 vendored 拷贝**,不是本项目自研代码。合规要务:随源码保留
|
||||
了上游的 `LICENSE`(Apache-2.0)与 `NOTICE`(Apache-2.0 第 4 条要求),**不得删除**。
|
||||
|
||||
## 出处(可复现)
|
||||
|
||||
| 项 | 值 |
|
||||
|---|---|
|
||||
| 仓库 | https://github.com/VoiceBlender/goamr-nb |
|
||||
| 版本 | `v1.0.0`(tag) |
|
||||
| 上游提交 | `635f7966829a0e5d01030355e36aa6792352c57e` |
|
||||
| 上游发布时间 | 2026-06-14T17:25:04Z(模块代理 `.info`) |
|
||||
| 取得方式 | 模块代理 `https://goproxy.cn/github.com/%21voice%21blender/goamr-nb/@v/v1.0.0.zip`(sha256 `663140d606646d62d6660e8ff8930725826680b4373055e6aeeab55f858f6067`) |
|
||||
| 许可证 | **Apache-2.0**(`LICENSE` + `NOTICE` 均逐字保留) |
|
||||
| 上游依赖 | 仅 `golang.org/x/sys`(`simd_amd64.go` 用 `x/sys/cpu` 判 AVX2);本仓库 `go.mod` 已有 `golang.org/x/sys v0.47.0`,**未新增任何模块依赖** |
|
||||
|
||||
## 为什么是「拷进仓库」而不是 `require`
|
||||
|
||||
上游是 2026-06 新建、**1 个提交 / 1 个 tag / 2 star** 的仓库。当外部依赖用等于把
|
||||
**构建**押在一个随时可能消失的仓库上;而 AMR-NB 是**冻结编解码**(1999 定标),
|
||||
拷进来基本不需要维护。因此:`go.mod` **不加** require,源码在本目录内自持。
|
||||
|
||||
## 拷了什么 / 没拷什么
|
||||
|
||||
- **拷了**:上游全部 57 个非测试 `.go` 文件 + `LICENSE` + `NOTICE`,逐字未改。
|
||||
- **没拷**:上游 48 个 `*_test.go`(含 `dsp_diff_test.go` 这类需要外部 C 参考
|
||||
harness 的测试)与 `Makefile` / `README.md`。本项目的正确性证据在
|
||||
`../codec_amr_nb_test.go`(ffmpeg/libopencore_amrnb 黄金向量),不依赖上游测试。
|
||||
- **本地新增**:`vendored_export.go`(导出桥,见其文件头说明)与本文档。
|
||||
除这两个文件外,本目录内容与上游一致。
|
||||
|
||||
## 已知能力边界(上游自述,实测确认;上游 README 的 `bit-exact` 说法**不覆盖**下列)
|
||||
|
||||
`dsp_decoder.go:13` 的注释写明:**`Cb_gain_average`(增益平滑)与自适应相位色散
|
||||
(phase dispersion)尚未移植**;`dsp.go:68` 写明**错误隐藏(bad frame)与 CNG
|
||||
(SID 舒适噪声)尚未移植**。
|
||||
|
||||
实测结论(本项目 2026-10-05,fixture 见 `../testdata/`):
|
||||
坏帧 / SID / no-data 帧**返回 160 样本静音**(不报错、不做隐藏);好帧解码与
|
||||
`opencore-amrnb`(ffmpeg `libopencore_amrnb`)**逐字节不一致**,样本级差值的量级见
|
||||
`../codec_amr_nb_test.go` 里记录的实测基线(SNR 约 16–21 dB,波形相关系数 ≥0.987,
|
||||
长度/帧数/时长**完全一致**)。可听、可播、内容正确,但**不是**参考位精确实现。
|
||||
|
||||
另注:`dsp.go` 顶部的「DSP 目前是 STUBBED」注释已过期(上游未同步)——
|
||||
`dsp_decoder.go` 里的解码 DSP 是完整实现,实测能解出真实语音。
|
||||
|
||||
## 交叉编译
|
||||
|
||||
纯 Go(`CGO_ENABLED=0` 可构建)。`simd_amd64.s` 是唯一非 Go 源文件,
|
||||
`simd_noasm.go` 提供 `!amd64` 的纯 Go 兜底 ⇒ `GOOS=linux/darwin` 交叉编译通过。
|
||||
@@ -0,0 +1,103 @@
|
||||
package amrnb
|
||||
|
||||
import "errors"
|
||||
|
||||
// Encoder encodes 8 kHz mono PCM into AMR-NB RFC 4867 RTP payloads.
|
||||
//
|
||||
// It satisfies the codec.Encoder interface: Encode takes one 20 ms frame
|
||||
// (160 int16 samples) and returns a complete RTP payload (CMR + ToC + speech
|
||||
// bits) in the configured payload format.
|
||||
type Encoder struct {
|
||||
mode Mode
|
||||
octetAligned bool
|
||||
st encoderState
|
||||
}
|
||||
|
||||
// EncoderConfig configures a new AMR-NB encoder.
|
||||
type EncoderConfig struct {
|
||||
Mode Mode // active speech mode (0..7)
|
||||
OctetAligned bool // true: octet-aligned framing; false: bandwidth-efficient
|
||||
}
|
||||
|
||||
// NewEncoder creates an AMR-NB encoder for the given mode and payload format.
|
||||
func NewEncoder(cfg EncoderConfig) (*Encoder, error) {
|
||||
if !cfg.Mode.Valid() {
|
||||
return nil, errors.New("amrnb: invalid encoder mode")
|
||||
}
|
||||
e := &Encoder{mode: cfg.Mode, octetAligned: cfg.OctetAligned}
|
||||
e.st.reset()
|
||||
return e, nil
|
||||
}
|
||||
|
||||
// Encode encodes one 20 ms frame (160 samples) into an RTP payload.
|
||||
func (e *Encoder) Encode(samples []int16) ([]byte, error) {
|
||||
if len(samples) != FrameSamples {
|
||||
return nil, errors.New("amrnb: encode expects exactly 160 samples")
|
||||
}
|
||||
bits, err := e.st.encodeFrame(e.mode, samples)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f := frame{ft: e.mode.FrameType(), q: true, data: bits}
|
||||
if e.octetAligned {
|
||||
return packPayloadOctet(noCMR, []frame{f}), nil
|
||||
}
|
||||
return packPayloadBandwidthEfficient(noCMR, []frame{f}), nil
|
||||
}
|
||||
|
||||
// SetMode changes the active speech mode (e.g. in response to a peer CMR).
|
||||
func (e *Encoder) SetMode(m Mode) {
|
||||
if m.Valid() {
|
||||
e.mode = m
|
||||
}
|
||||
}
|
||||
|
||||
// Reset clears all encoder state.
|
||||
func (e *Encoder) Reset() { e.st.reset() }
|
||||
|
||||
// Decoder decodes AMR-NB RFC 4867 RTP payloads into 8 kHz mono PCM.
|
||||
type Decoder struct {
|
||||
octetAligned bool
|
||||
st decoderState
|
||||
}
|
||||
|
||||
// DecoderConfig configures a new AMR-NB decoder.
|
||||
type DecoderConfig struct {
|
||||
OctetAligned bool // must match the negotiated payload format
|
||||
}
|
||||
|
||||
// NewDecoder creates an AMR-NB decoder for the given payload format.
|
||||
func NewDecoder(cfg DecoderConfig) *Decoder {
|
||||
d := &Decoder{octetAligned: cfg.OctetAligned}
|
||||
d.st.reset()
|
||||
return d
|
||||
}
|
||||
|
||||
// Decode decodes one RTP payload, returning concatenated PCM for all frames it
|
||||
// carries (one 160-sample frame per speech/SID/no-data ToC entry).
|
||||
func (d *Decoder) Decode(payload []byte) ([]int16, error) {
|
||||
var (
|
||||
frames []frame
|
||||
err error
|
||||
)
|
||||
if d.octetAligned {
|
||||
_, frames, err = unpackPayloadOctet(payload)
|
||||
} else {
|
||||
_, frames, err = unpackPayloadBandwidthEfficient(payload)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out := make([]int16, 0, len(frames)*FrameSamples)
|
||||
for _, f := range frames {
|
||||
pcm, derr := d.st.decodeFrame(f)
|
||||
if derr != nil {
|
||||
return nil, derr
|
||||
}
|
||||
out = append(out, pcm...)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Reset clears all decoder state.
|
||||
func (d *Decoder) Reset() { d.st.reset() }
|
||||
@@ -0,0 +1,261 @@
|
||||
package amrnb
|
||||
|
||||
// Fixed-point basic operators, ported from the ITU-T / ETSI "basicop2"
|
||||
// reference (the same primitives used by opencore-amrnb).
|
||||
//
|
||||
// Word16 maps to int16, Word32 to int32. All operators saturate to the 16- or
|
||||
// 32-bit range exactly as the reference does; Go has no implicit integer
|
||||
// saturation, so every operation that can overflow clamps explicitly. The
|
||||
// reference's global Overflow/Carry flags are not modelled — no AMR-NB code
|
||||
// path depends on reading them back.
|
||||
|
||||
const (
|
||||
maxInt16 = 32767
|
||||
minInt16 = -32768
|
||||
maxInt32 = 2147483647
|
||||
minInt32 = -2147483648
|
||||
)
|
||||
|
||||
// satWord16 clamps a 32-bit value to the int16 range.
|
||||
func satWord16(v int32) int16 {
|
||||
if v > maxInt16 {
|
||||
return maxInt16
|
||||
}
|
||||
if v < minInt16 {
|
||||
return minInt16
|
||||
}
|
||||
return int16(v)
|
||||
}
|
||||
|
||||
// satWord32 clamps a 64-bit value to the int32 range.
|
||||
func satWord32(v int64) int32 {
|
||||
if v > maxInt32 {
|
||||
return maxInt32
|
||||
}
|
||||
if v < minInt32 {
|
||||
return minInt32
|
||||
}
|
||||
return int32(v)
|
||||
}
|
||||
|
||||
// add returns the saturated 16-bit sum a+b.
|
||||
func add(a, b int16) int16 { return satWord16(int32(a) + int32(b)) }
|
||||
|
||||
// sub returns the saturated 16-bit difference a-b.
|
||||
func sub(a, b int16) int16 { return satWord16(int32(a) - int32(b)) }
|
||||
|
||||
// abs_s returns the saturated 16-bit absolute value (|-32768| -> 32767).
|
||||
func abs_s(a int16) int16 {
|
||||
if a == minInt16 {
|
||||
return maxInt16
|
||||
}
|
||||
if a < 0 {
|
||||
return -a
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// shl returns a shifted left by b bits with saturation; negative b shifts right.
|
||||
func shl(a, b int16) int16 {
|
||||
if b < 0 {
|
||||
return shr(a, -b)
|
||||
}
|
||||
result := int32(a) << uint(b)
|
||||
// Detect overflow by checking the shift is reversible.
|
||||
if b >= 31 {
|
||||
if a == 0 {
|
||||
return 0
|
||||
}
|
||||
if a > 0 {
|
||||
return maxInt16
|
||||
}
|
||||
return minInt16
|
||||
}
|
||||
return satWord16(result)
|
||||
}
|
||||
|
||||
// shr returns a shifted right by b bits (arithmetic); negative b shifts left.
|
||||
func shr(a, b int16) int16 {
|
||||
if b < 0 {
|
||||
return shl(a, -b)
|
||||
}
|
||||
if b >= 15 {
|
||||
if a < 0 {
|
||||
return -1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
return int16(int32(a) >> uint(b))
|
||||
}
|
||||
|
||||
// L_shl returns the saturated 32-bit left shift; negative b shifts right.
|
||||
func L_shl(a int32, b int16) int32 {
|
||||
if b <= 0 {
|
||||
if b == 0 {
|
||||
return a
|
||||
}
|
||||
return L_shr(a, -b)
|
||||
}
|
||||
if b >= 31 {
|
||||
if a > 0 {
|
||||
return maxInt32
|
||||
}
|
||||
if a < 0 {
|
||||
return minInt32
|
||||
}
|
||||
return 0
|
||||
}
|
||||
// The reference shifts one bit at a time, saturating as soon as the value
|
||||
// reaches the overflow region. Since |a<<k| grows monotonically, saturation
|
||||
// is decided by the last pre-shift value a<<(b-1): >= 2^30 -> MAX_32,
|
||||
// < -2^30 -> MIN_32; otherwise a<<b fits. Computed in int64 this is O(1) and
|
||||
// bit-identical to the loop.
|
||||
last := int64(a) << uint(b-1)
|
||||
if last >= 0x40000000 {
|
||||
return maxInt32
|
||||
}
|
||||
if last < -0x40000000 {
|
||||
return minInt32
|
||||
}
|
||||
return a << uint(b)
|
||||
}
|
||||
|
||||
// L_shr returns the 32-bit arithmetic right shift; negative b shifts left.
|
||||
func L_shr(a int32, b int16) int32 {
|
||||
if b < 0 {
|
||||
return L_shl(a, -b)
|
||||
}
|
||||
if b >= 31 {
|
||||
if a < 0 {
|
||||
return -1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
return a >> uint(b)
|
||||
}
|
||||
|
||||
// mult returns satWord16((a*b)>>15).
|
||||
func mult(a, b int16) int16 {
|
||||
p := (int32(a) * int32(b)) >> 15
|
||||
return satWord16(p)
|
||||
}
|
||||
|
||||
// L_mult returns satWord32(a*b<<1) — the 32-bit product with the fractional
|
||||
// left shift.
|
||||
func L_mult(a, b int16) int32 {
|
||||
p := int32(a) * int32(b)
|
||||
if p != 0x40000000 {
|
||||
return p << 1
|
||||
}
|
||||
return maxInt32
|
||||
}
|
||||
|
||||
// L_add returns the saturated 32-bit sum.
|
||||
func L_add(a, b int32) int32 { return satWord32(int64(a) + int64(b)) }
|
||||
|
||||
// L_sub returns the saturated 32-bit difference.
|
||||
func L_sub(a, b int32) int32 { return satWord32(int64(a) - int64(b)) }
|
||||
|
||||
// L_mac returns acc + (a*b<<1), saturated.
|
||||
func L_mac(acc int32, a, b int16) int32 { return L_add(acc, L_mult(a, b)) }
|
||||
|
||||
// L_msu returns acc - (a*b<<1), saturated.
|
||||
func L_msu(acc int32, a, b int16) int32 { return L_sub(acc, L_mult(a, b)) }
|
||||
|
||||
// negate returns the saturated 16-bit negation.
|
||||
func negate(a int16) int16 {
|
||||
if a == minInt16 {
|
||||
return maxInt16
|
||||
}
|
||||
return -a
|
||||
}
|
||||
|
||||
// L_negate returns the saturated 32-bit negation.
|
||||
func L_negate(a int32) int32 {
|
||||
if a == minInt32 {
|
||||
return maxInt32
|
||||
}
|
||||
return -a
|
||||
}
|
||||
|
||||
// extract_h returns the high 16 bits of a 32-bit value.
|
||||
func extract_h(a int32) int16 { return int16(a >> 16) }
|
||||
|
||||
// extract_l returns the low 16 bits of a 32-bit value.
|
||||
func extract_l(a int32) int16 { return int16(a & 0xFFFF) }
|
||||
|
||||
// round_ returns the rounded high word: extract_h(L_add(a, 0x8000)).
|
||||
func round_(a int32) int16 { return extract_h(L_add(a, 0x8000)) }
|
||||
|
||||
// mult_r returns the rounded multiply: satWord16(((a*b)+0x4000)>>15).
|
||||
func mult_r(a, b int16) int16 {
|
||||
p := (int32(a)*int32(b) + 0x4000) >> 15
|
||||
return satWord16(p)
|
||||
}
|
||||
|
||||
// L_deposit_h places a 16-bit value in the high half of a 32-bit word.
|
||||
func L_deposit_h(a int16) int32 { return int32(a) << 16 }
|
||||
|
||||
// L_deposit_l sign-extends a 16-bit value into a 32-bit word.
|
||||
func L_deposit_l(a int16) int32 { return int32(a) }
|
||||
|
||||
// norm_l returns the number of left shifts needed to normalize a (0 for 0).
|
||||
func norm_l(a int32) int16 {
|
||||
if a == 0 {
|
||||
return 0
|
||||
}
|
||||
if a == -1 {
|
||||
return 31
|
||||
}
|
||||
if a < 0 {
|
||||
a = ^a
|
||||
}
|
||||
var n int16
|
||||
for a < 0x40000000 {
|
||||
a <<= 1
|
||||
n++
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// norm_s returns the number of left shifts needed to normalize a 16-bit value.
|
||||
func norm_s(a int16) int16 {
|
||||
if a == 0 {
|
||||
return 0
|
||||
}
|
||||
if a == -1 {
|
||||
return 15
|
||||
}
|
||||
v := a
|
||||
if v < 0 {
|
||||
v = ^v
|
||||
}
|
||||
var n int16
|
||||
for v < 0x4000 {
|
||||
v <<= 1
|
||||
n++
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// div_s returns the fractional division (a/b)<<15 for 0 <= a <= b, b != 0.
|
||||
func div_s(a, b int16) int16 {
|
||||
if a == 0 {
|
||||
return 0
|
||||
}
|
||||
if a == b {
|
||||
return maxInt16
|
||||
}
|
||||
num := int32(a)
|
||||
den := int32(b)
|
||||
var quot int32
|
||||
for i := 0; i < 15; i++ {
|
||||
quot <<= 1
|
||||
num <<= 1
|
||||
if num >= den {
|
||||
num -= den
|
||||
quot++
|
||||
}
|
||||
}
|
||||
return int16(quot)
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package amrnb
|
||||
|
||||
// This file holds the AMR-NB signal-processing state and the entry points the
|
||||
// public Encoder/Decoder call per 20 ms frame. The fixed-point DSP itself
|
||||
// (LP analysis/LSF quantization, open/closed-loop pitch, algebraic codebook
|
||||
// search, gain quantization, synthesis and post-filtering, DTX) is a large
|
||||
// bit-exact port of 3GPP TS 26.090 — see opencore-amrnb (Apache-2.0), which
|
||||
// ships both encoder and decoder.
|
||||
//
|
||||
// The structs below define where that ported state lives. The encodeFrame /
|
||||
// decodeFrame methods are the single integration seam where the per-block DSP
|
||||
// functions are orchestrated per 20 ms frame.
|
||||
//
|
||||
// NOTE: the DSP is currently STUBBED — coder()/decoder() are not yet ported, so
|
||||
// encodeFrame emits a zero-filled bitstream of the correct size and decodeFrame
|
||||
// emits silence. The public API, RFC 4867 framing, fixed-point operators and
|
||||
// SIMD kernels are complete and exercised by the pure-Go tests; the bit-exact
|
||||
// DSP lands in a later phase (see the plan).
|
||||
|
||||
// encoderState holds the persistent encoder analysis state across frames.
|
||||
type encoderState struct {
|
||||
started bool
|
||||
st coderState
|
||||
}
|
||||
|
||||
func (s *encoderState) reset() {
|
||||
s.started = true
|
||||
s.st.reset()
|
||||
}
|
||||
|
||||
// encodeFrame analyses one 160-sample frame in the given mode and returns the
|
||||
// RFC 4867 frame payload bytes (the sorted/packed speech bits, without the
|
||||
// CMR/ToC header which the caller adds). Mirrors Speech_Encode_Frame: mask the 3
|
||||
// LSBs (13-bit input), high-pass + downscale (Pre_Process), run the analysis
|
||||
// (cod_amr), then serialize (prm2bits + IETF reorder via packFrame).
|
||||
func (s *encoderState) encodeFrame(mode Mode, samples []int16) ([]byte, error) {
|
||||
if !s.started {
|
||||
s.reset()
|
||||
}
|
||||
in := make([]int16, cL_FRAME)
|
||||
for i := 0; i < cL_FRAME && i < len(samples); i++ {
|
||||
in[i] = samples[i] &^ 7 // delete 3 LSBs (13-bit input)
|
||||
}
|
||||
s.st.pre.process(in, cL_FRAME)
|
||||
|
||||
prm, err := s.st.codAmr(int(mode), in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return packFrame(prm, mode), nil
|
||||
}
|
||||
|
||||
// decoderState holds the persistent decoder synthesis state across frames.
|
||||
type decoderState struct {
|
||||
dsp decoderStateDSP
|
||||
lastMode Mode
|
||||
started bool
|
||||
}
|
||||
|
||||
func (s *decoderState) reset() {
|
||||
s.dsp.reset()
|
||||
s.lastMode = Mode1220
|
||||
s.started = true
|
||||
}
|
||||
|
||||
// decodeFrame decodes one parsed AMR-NB frame into 160 PCM samples. Good speech
|
||||
// frames are fully decoded; bad/SID/no-data frames currently emit silence
|
||||
// (error concealment and CNG are not yet ported).
|
||||
func (s *decoderState) decodeFrame(f frame) ([]int16, error) {
|
||||
if !s.started {
|
||||
s.reset()
|
||||
}
|
||||
synth := make([]int16, cAMR_NB_PCM_FRAME)
|
||||
if f.ft <= FTMode1220 { // speech
|
||||
mode := Mode(f.ft)
|
||||
s.lastMode = mode
|
||||
if f.q {
|
||||
params := mimeUnsort(f.data, mode)
|
||||
s.dsp.decodeSpeechFrame(int(mode), params, synth)
|
||||
}
|
||||
}
|
||||
return synth, nil
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
package amrnb
|
||||
|
||||
// Adaptive-codebook (pitch) reconstruction, ported from opencore-amrnb
|
||||
// pred_lt.cpp, dec_lag3.cpp and dec_lag6.cpp. predLt interpolates the past
|
||||
// excitation at a fractional pitch lag to build this subframe's adaptive
|
||||
// codebook contribution; decLag3/decLag6 turn the received pitch index into an
|
||||
// integer lag T0 and a fractional part. Bit-exact with the reference.
|
||||
|
||||
const (
|
||||
cL_INTER10 = 10 // interpolation FIR half-context (L_INTERPOL-1)
|
||||
cUP_SAMP_MAX = 6 // fractional pitch upsampling factor
|
||||
)
|
||||
|
||||
// predLt computes the interpolated past excitation for the current subframe in
|
||||
// place: exc[pos : pos+Lsubfr] is overwritten using exc[pos-T0 ...] convolved
|
||||
// with the 1/6-resolution FIR selected by frac. For short lags (T0 < Lsubfr)
|
||||
// the loop deliberately reads samples it just wrote, matching the reference.
|
||||
// Mirrors Pred_lt_3or6.
|
||||
func predLt(exc []int16, pos int, T0, frac, Lsubfr, flag3 int16) {
|
||||
var coeff [2 * cL_INTER10]int16
|
||||
|
||||
pX0 := pos - int(T0)
|
||||
frac = -frac
|
||||
if flag3 != 0 {
|
||||
frac <<= 1 // inter_3l[k] = inter_6[2k]
|
||||
}
|
||||
if frac < 0 {
|
||||
frac += cUP_SAMP_MAX
|
||||
pX0--
|
||||
}
|
||||
f := int(frac)
|
||||
|
||||
k := 0
|
||||
ci := 0
|
||||
for i := cL_INTER10 >> 1; i > 0; i-- {
|
||||
coeff[ci] = inter_6_pred_lt[f+k]
|
||||
coeff[ci+1] = inter_6_pred_lt[(cUP_SAMP_MAX-f)+k]
|
||||
ci += 2
|
||||
k += cUP_SAMP_MAX
|
||||
coeff[ci] = inter_6_pred_lt[f+k]
|
||||
coeff[ci+1] = inter_6_pred_lt[(cUP_SAMP_MAX-f)+k]
|
||||
ci += 2
|
||||
k += cUP_SAMP_MAX
|
||||
}
|
||||
|
||||
pExc := pos
|
||||
for j := int(Lsubfr) >> 1; j != 0; j-- {
|
||||
pX0++
|
||||
ix2 := pX0
|
||||
ix3 := pX0
|
||||
pX0++
|
||||
|
||||
ic := 0
|
||||
s1 := int32(0x4000)
|
||||
s2 := int32(0x4000)
|
||||
for i := cL_INTER10 >> 1; i > 0; i-- {
|
||||
s2 += int32(exc[ix3]) * int32(coeff[ic])
|
||||
ix3--
|
||||
s1 += int32(exc[ix3]) * int32(coeff[ic])
|
||||
ic++
|
||||
s1 += int32(exc[ix2]) * int32(coeff[ic])
|
||||
ix2++
|
||||
s2 += int32(exc[ix2]) * int32(coeff[ic])
|
||||
ic++
|
||||
s2 += int32(exc[ix3]) * int32(coeff[ic])
|
||||
ix3--
|
||||
s1 += int32(exc[ix3]) * int32(coeff[ic])
|
||||
ic++
|
||||
s1 += int32(exc[ix2]) * int32(coeff[ic])
|
||||
ix2++
|
||||
s2 += int32(exc[ix2]) * int32(coeff[ic])
|
||||
ic++
|
||||
}
|
||||
exc[pExc] = int16(s1 >> 15)
|
||||
pExc++
|
||||
exc[pExc] = int16(s2 >> 15)
|
||||
pExc++
|
||||
}
|
||||
}
|
||||
|
||||
// decLag3 decodes the 1/3-resolution pitch lag (used by most modes) from the
|
||||
// received index into an integer lag T0 and fractional part T0frac. i_subfr==0
|
||||
// marks the 1st/3rd subframe (absolute coding); otherwise the lag is coded
|
||||
// relative to t0_min (or, with flag4, to T0prev). Mirrors Dec_lag3.
|
||||
func decLag3(index, t0Min, t0Max, iSubfr, T0prev, flag4 int16) (T0, T0frac int16) {
|
||||
var i, tmpLag int16
|
||||
if iSubfr == 0 { // 1st or 3rd subframe
|
||||
if index < 197 {
|
||||
tmpLag = index + 2
|
||||
tmpLag = mult(tmpLag, 10923)
|
||||
i = tmpLag + 19
|
||||
T0 = i
|
||||
i <<= 1
|
||||
i += T0
|
||||
tmpLag = index - i
|
||||
T0frac = tmpLag + 58
|
||||
} else {
|
||||
T0 = index - 112
|
||||
T0frac = 0
|
||||
}
|
||||
} else { // 2nd or 4th subframe
|
||||
if flag4 == 0 {
|
||||
i = index + 2
|
||||
i = int16((int32(i) * 10923) >> 15)
|
||||
i -= 1
|
||||
T0 = i + t0Min
|
||||
i = i + (i << 1)
|
||||
tmpLag = index - 2
|
||||
T0frac = tmpLag - i
|
||||
} else {
|
||||
tmpLag = T0prev
|
||||
i = sub(tmpLag, t0Min)
|
||||
if i > 5 {
|
||||
tmpLag = t0Min + 5
|
||||
}
|
||||
i = t0Max - tmpLag
|
||||
if i > 4 {
|
||||
tmpLag = t0Max - 4
|
||||
}
|
||||
if index < 4 {
|
||||
i = tmpLag - 5
|
||||
T0 = i + index
|
||||
T0frac = 0
|
||||
} else if index < 12 {
|
||||
i = index - 5
|
||||
i = int16((int32(i) * 10923) >> 15)
|
||||
i--
|
||||
T0 = i + tmpLag
|
||||
i = i + (i << 1)
|
||||
tmpLag = index - 9
|
||||
T0frac = tmpLag - i
|
||||
} else {
|
||||
i = index - 12
|
||||
i = i + tmpLag
|
||||
T0 = i + 1
|
||||
T0frac = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
return T0, T0frac
|
||||
}
|
||||
|
||||
// decLag6 decodes the 1/6-resolution pitch lag (MR122) from the received index.
|
||||
// T0in supplies the previous subframe's integer lag for the relative (2nd/4th)
|
||||
// subframe path. Mirrors Dec_lag6.
|
||||
func decLag6(index, pitMin, pitMax, iSubfr, T0in int16) (T0, T0frac int16) {
|
||||
var i, T0min, T0max, k int16
|
||||
if iSubfr == 0 { // 1st or 3rd subframe
|
||||
if index < 463 {
|
||||
i = index + 5
|
||||
i = int16((int32(i) * 5462) >> 15)
|
||||
i += 17
|
||||
T0 = i
|
||||
i <<= 1
|
||||
i += T0
|
||||
i <<= 1
|
||||
i = index - i
|
||||
T0frac = i + 105
|
||||
} else {
|
||||
T0 = index - 368
|
||||
T0frac = 0
|
||||
}
|
||||
} else { // 2nd or 4th subframe
|
||||
T0min = T0in - 5
|
||||
if T0min < pitMin {
|
||||
T0min = pitMin
|
||||
}
|
||||
T0max = T0min + 9
|
||||
if T0max > pitMax {
|
||||
T0max = pitMax
|
||||
T0min = T0max - 9
|
||||
}
|
||||
i = index + 5
|
||||
i = int16((int32(i) * 5462) >> 15)
|
||||
i -= 1
|
||||
T0 = i + T0min
|
||||
i = i + (i << 1)
|
||||
i <<= 1
|
||||
k = index - 3
|
||||
T0frac = k - i
|
||||
}
|
||||
return T0, T0frac
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package amrnb
|
||||
|
||||
// Adaptive gain control for the post-filter, ported from opencore-amrnb agc.cpp.
|
||||
// agc scales the post-filtered signal so its energy tracks the synthesis
|
||||
// energy, with a per-sample gain smoothed by agc_fac across the subframe. The
|
||||
// running gain is carried in agcState. Bit-exact with the reference.
|
||||
|
||||
const cAGC_FAC = 29491 // 0.9, the post-filter AGC factor
|
||||
|
||||
// agcState holds the smoothed per-sample gain across subframes.
|
||||
type agcState struct {
|
||||
pastGain int16
|
||||
}
|
||||
|
||||
// energyOld accumulates the energy of a prescaled signal (used when energyNew
|
||||
// would overflow). Mirrors energy_old.
|
||||
func energyOld(in []int16, lTrm int) int32 {
|
||||
var s int32
|
||||
for i := 0; i < lTrm; i++ {
|
||||
temp := in[i] >> 2
|
||||
s = L_mac(s, temp, temp)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// energyNew returns the energy of a signal (>>4 scaled), falling back to
|
||||
// energyOld on saturation. Mirrors energy_new.
|
||||
func energyNew(in []int16, lTrm int) int32 {
|
||||
var s int32
|
||||
for i := 0; i < lTrm; i++ {
|
||||
s = L_mac(s, in[i], in[i])
|
||||
}
|
||||
if s != maxInt32 {
|
||||
return s >> 4
|
||||
}
|
||||
return energyOld(in, lTrm)
|
||||
}
|
||||
|
||||
// agc scales sigOut in place so its energy approaches sigIn's, applying a gain
|
||||
// smoothed across the subframe by agcFac and carried in the state. Mirrors agc.
|
||||
func (st *agcState) agc(sigIn, sigOut []int16, agcFac int16, lTrm int) {
|
||||
s := energyNew(sigOut, lTrm)
|
||||
if s == 0 {
|
||||
st.pastGain = 0
|
||||
return
|
||||
}
|
||||
exp := norm_l(s) - 1
|
||||
gainOut := round_(L_shl(s, exp))
|
||||
|
||||
s = energyNew(sigIn, lTrm)
|
||||
var g0 int16
|
||||
if s == 0 {
|
||||
g0 = 0
|
||||
} else {
|
||||
i := norm_l(s)
|
||||
gainIn := round_(s << i)
|
||||
exp -= i
|
||||
|
||||
temp := div_s(gainOut, gainIn)
|
||||
ss := int32(temp) << 7
|
||||
ss = L_shr(ss, exp)
|
||||
ss = invSqrt(ss)
|
||||
lTemp := ss << 9
|
||||
ii := int16((lTemp + 0x8000) >> 16)
|
||||
temp = 32767 - agcFac
|
||||
g0 = int16((int32(ii) * int32(temp)) >> 15)
|
||||
}
|
||||
|
||||
gain := st.pastGain
|
||||
for i := 0; i < lTrm; i++ {
|
||||
gain = int16((int32(gain) * int32(agcFac)) >> 15)
|
||||
gain += g0
|
||||
lTemp := (int32(sigOut[i]) * int32(gain)) << 1
|
||||
sigOut[i] = int16(lTemp >> 13)
|
||||
}
|
||||
st.pastGain = gain
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package amrnb
|
||||
|
||||
// A(z) -> LSP conversion, ported from opencore-amrnb az_lsp.cpp (Chebps, Az_lsp).
|
||||
// Az_lsp finds the line spectral pairs of an order-10 LP filter by locating the
|
||||
// roots of the symmetric/antisymmetric polynomials F1(z)/F2(z) on the unit
|
||||
// circle, evaluated via the Chebyshev recursion (Chebps) over the cosine grid.
|
||||
// This is the encoder-side inverse of lspAz. Bit-exact with the reference.
|
||||
|
||||
const cNC = cM / 2 // 5
|
||||
|
||||
// chebps evaluates the Chebyshev series of f at x. Mirrors Chebps.
|
||||
func chebps(x int16, f []int16, n int) int16 {
|
||||
pf := 1
|
||||
lTemp := int32(0x01000000)
|
||||
t0 := (int32(x) << 10) + (int32(f[pf]) << 14)
|
||||
pf++
|
||||
b1h := int16(t0 >> 16)
|
||||
b1l := int16((t0 >> 1) - (int32(b1h) << 15))
|
||||
|
||||
for i := 2; i < n; i++ {
|
||||
t0 = int32(b1h) * int32(x)
|
||||
t0 += (int32(b1l) * int32(x)) >> 15
|
||||
t0 <<= 2
|
||||
t0 -= lTemp
|
||||
t0 += int32(f[pf]) << 14
|
||||
pf++
|
||||
lTemp = (int32(b1h) << 16) + (int32(b1l) << 1)
|
||||
b1h = int16(t0 >> 16)
|
||||
b1l = int16((t0 >> 1) - (int32(b1h) << 15))
|
||||
}
|
||||
|
||||
t0 = int32(b1h) * int32(x)
|
||||
t0 += (int32(b1l) * int32(x)) >> 15
|
||||
t0 <<= 1
|
||||
t0 -= lTemp
|
||||
t0 += int32(f[pf]) << 13
|
||||
|
||||
if uint32(t0+33554432) < 67108863 {
|
||||
return int16(t0 >> 10)
|
||||
} else if t0 > 0x01ffffff {
|
||||
return maxInt16
|
||||
}
|
||||
return minInt16
|
||||
}
|
||||
|
||||
// azLsp converts order-10 LP coefficients a[0:M+1] to line spectral pairs
|
||||
// lsp[0:M]. oldLsp is reused if fewer than M roots are found. Mirrors Az_lsp.
|
||||
func azLsp(a, lsp, oldLsp []int16) {
|
||||
var f1, f2 [cNC + 1]int16
|
||||
f1[0] = 1024
|
||||
f2[0] = 1024
|
||||
for i := 0; i < cNC; i++ {
|
||||
lt1 := int32(a[i+1])
|
||||
lt2 := int32(a[cM-i])
|
||||
x := int16((lt1 + lt2) >> 2)
|
||||
y := int16((lt1 - lt2) >> 2)
|
||||
x -= f1[i]
|
||||
f1[i+1] = x
|
||||
y += f2[i]
|
||||
f2[i+1] = y
|
||||
}
|
||||
|
||||
nf := 0
|
||||
ip := 0
|
||||
coef := f1[:]
|
||||
|
||||
xlow := grid[0]
|
||||
ylow := chebps(xlow, coef, cNC)
|
||||
|
||||
j := 0
|
||||
for nf < cM && j < 60 {
|
||||
j++
|
||||
xhigh := xlow
|
||||
yhigh := ylow
|
||||
xlow = grid[j]
|
||||
ylow = chebps(xlow, coef, cNC)
|
||||
|
||||
if int32(ylow)*int32(yhigh) <= 0 {
|
||||
for i := 4; i != 0; i-- {
|
||||
xmid := (xlow >> 1) + (xhigh >> 1)
|
||||
ymid := chebps(xmid, coef, cNC)
|
||||
if int32(ylow)*int32(ymid) <= 0 {
|
||||
yhigh = ymid
|
||||
xhigh = xmid
|
||||
} else {
|
||||
ylow = ymid
|
||||
xlow = xmid
|
||||
}
|
||||
}
|
||||
|
||||
x := xhigh - xlow
|
||||
yv := yhigh - ylow
|
||||
var xint int16
|
||||
if yv == 0 {
|
||||
xint = xlow
|
||||
} else {
|
||||
sign := yv
|
||||
yv = abs_s(yv)
|
||||
exp := norm_s(yv)
|
||||
yv = shl(yv, exp)
|
||||
yv = div_s(16383, yv)
|
||||
yv = int16((int32(x) * int32(yv)) >> uint(19-exp))
|
||||
if sign < 0 {
|
||||
yv = -yv
|
||||
}
|
||||
xint = int16(int32(xlow) - ((int32(ylow) * int32(yv)) >> 10))
|
||||
}
|
||||
|
||||
lsp[nf] = xint
|
||||
xlow = xint
|
||||
nf++
|
||||
|
||||
if ip == 0 {
|
||||
ip = 1
|
||||
coef = f2[:]
|
||||
} else {
|
||||
ip = 0
|
||||
coef = f1[:]
|
||||
}
|
||||
ylow = chebps(xlow, coef, cNC)
|
||||
}
|
||||
}
|
||||
|
||||
if nf < cM {
|
||||
copy(lsp[:cM], oldLsp[:cM])
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package amrnb
|
||||
|
||||
// Decoder-side bit de-serialization, ported from opencore-amrnb bits2prm.cpp
|
||||
// (Bin2int/Bits2prm) and the IETF->ETS reordering in wmf_to_ets.cpp (used for
|
||||
// MIME_IETF input). The chain inverts the encoder side: IETF storage bytes ->
|
||||
// ETS serial bits (unpacked MSB-first then inverse-permuted by reorderBits) ->
|
||||
// parameter array (each parameter read MSB-first from its bitno width).
|
||||
|
||||
// bin2int reads nBits from bits[0:nBits], MSB first (bits[0] is the most
|
||||
// significant bit), and returns the assembled value. Mirrors Bin2int.
|
||||
func bin2int(nBits int, bits []int16) int16 {
|
||||
var v int16
|
||||
for i := 0; i < nBits; i++ {
|
||||
v = (v << 1) | (bits[i] & 1)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// ietfToEts unpacks the RFC 4867 speech payload bytes (IETF storage order,
|
||||
// MSB-first) and inverse-permutes them via reorderBits[mode] into the ETS
|
||||
// serial bit array. Mirrors the speech branch of wmf_to_ets.
|
||||
func ietfToEts(mode Mode, data []byte) []int16 {
|
||||
nb := modeBits[mode]
|
||||
ro := reorderBits[mode]
|
||||
ets := make([]int16, nb)
|
||||
for i := 0; i < nb; i++ {
|
||||
bit := (data[i>>3] >> uint(7-(i&7))) & 1
|
||||
ets[ro[i]] = int16(bit)
|
||||
}
|
||||
return ets
|
||||
}
|
||||
|
||||
// bits2prm reads the ETS serial bit array back into the mode's parameter array.
|
||||
// Mirrors Bits2prm.
|
||||
func bits2prm(mode Mode, ets []int16) []int16 {
|
||||
bn := bitno[mode]
|
||||
prm := make([]int16, len(bn))
|
||||
pos := 0
|
||||
for i, w := range bn {
|
||||
prm[i] = bin2int(int(w), ets[pos:])
|
||||
pos += int(w)
|
||||
}
|
||||
return prm
|
||||
}
|
||||
|
||||
// mimeUnsort decodes the RFC 4867 speech payload bytes for the given mode into
|
||||
// the decoder parameter array (the inverse of packFrame).
|
||||
func mimeUnsort(data []byte, mode Mode) []int16 {
|
||||
return bits2prm(mode, ietfToEts(mode, data))
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package amrnb
|
||||
|
||||
// Core AMR-NB signal-processing constants, from opencore-amrnb cnst.h and
|
||||
// mode.h. AMR-NB codes 8 kHz speech in 20 ms frames of 160 samples, with an
|
||||
// order-10 LP filter and four 40-sample subframes.
|
||||
|
||||
const (
|
||||
cL_FRAME = 160 // frame size (samples)
|
||||
cL_FRAME_BY2 = 80 // frame size / 2
|
||||
cL_SUBFR = 40 // subframe size
|
||||
cL_CODE = 40 // codevector length
|
||||
cNB_SUBFR = 4 // subframes per frame
|
||||
cL_WINDOW = 240 // LP analysis window size
|
||||
cL_NEXT = 40 // LP analysis look-ahead
|
||||
cL_TOTAL = 320 // total speech analysis buffer
|
||||
cM = 10 // LP filter order
|
||||
cMP1 = 11 // LP filter order + 1
|
||||
cL_INTERPOL = 11 // interpolation filter length (10+1)
|
||||
cPIT_MIN = 20 // minimum pitch lag
|
||||
cPIT_MAX = 143 // maximum pitch lag
|
||||
|
||||
cAMR_NB_PCM_FRAME = 160 // PCM samples produced/consumed per frame
|
||||
cMAX_PRM_SIZE = 57 // max number of serial parameters (MR122)
|
||||
)
|
||||
|
||||
// Internal coding-mode enum, matching opencore-amrnb mode.h (enum Mode). These
|
||||
// are the DSP-side mode indices; the public Mode type shares the speech values
|
||||
// 0..7, with dMRDTX used for SID/comfort-noise handling.
|
||||
const (
|
||||
dMR475 = iota
|
||||
dMR515
|
||||
dMR59
|
||||
dMR67
|
||||
dMR74
|
||||
dMR795
|
||||
dMR102
|
||||
dMR122
|
||||
dMRDTX
|
||||
dNMODES
|
||||
)
|
||||
|
||||
// Receive frame types, matching opencore-amrnb enum RXFrameType. The decoder
|
||||
// driver maps RFC 4867 ToC frame types onto these.
|
||||
const (
|
||||
cRX_SPEECH_GOOD = iota
|
||||
cRX_SPEECH_DEGRADED
|
||||
cRX_ONSET
|
||||
cRX_SPEECH_BAD
|
||||
cRX_SID_FIRST
|
||||
cRX_SID_UPDATE
|
||||
cRX_SID_BAD
|
||||
cRX_NO_DATA
|
||||
cRX_N_FRAMETYPES
|
||||
)
|
||||
@@ -0,0 +1,262 @@
|
||||
package amrnb
|
||||
|
||||
// Per-mode algebraic (fixed) codebook decoders, ported from opencore-amrnb
|
||||
// d2_9pf.cpp, d2_11pf.cpp, d3_14pf.cpp, d4_17pf.cpp, d8_31pf.cpp and
|
||||
// d1035pf.cpp. Each reconstructs the 40-sample innovation vector cod[] from a
|
||||
// mode's pulse-position and sign indices (GSM-style tracks, Gray-coded for the
|
||||
// 4/8/10-pulse modes). Pulse amplitudes are ±8191/∓8192 (or ±4096 for MR122),
|
||||
// matching the reference exactly.
|
||||
|
||||
// pulse amplitude for the ±1.0 codebook entries (MR122 uses ±4096).
|
||||
const cPOS_CODE = 8191
|
||||
|
||||
// decode2i40_9bits decodes the 2-pulse codebook for MR475/MR515. Mirrors
|
||||
// decode_2i40_9bits (d2_9pf.cpp); subNr is the subframe number.
|
||||
func decode2i40_9bits(subNr, sign, index int16, cod []int16) {
|
||||
var pos [2]int16
|
||||
|
||||
j := index & 64
|
||||
j >>= 3
|
||||
i := index & 7
|
||||
k := shl(subNr, 1)
|
||||
k += j
|
||||
pos[0] = i*5 + startPos[k]
|
||||
k++
|
||||
|
||||
index >>= 3
|
||||
i = index & 7
|
||||
pos[1] = i*5 + startPos[k]
|
||||
|
||||
for n := 0; n < cL_SUBFR; n++ {
|
||||
cod[n] = 0
|
||||
}
|
||||
for j := 0; j < 2; j++ {
|
||||
s := sign & 0x1
|
||||
cod[pos[j]] = s*16383 - 8192
|
||||
sign >>= 1
|
||||
}
|
||||
}
|
||||
|
||||
// decode2i40_11bits decodes the 2-pulse codebook for MR59. Mirrors
|
||||
// decode_2i40_11bits (d2_11pf.cpp).
|
||||
func decode2i40_11bits(sign, index int16, cod []int16) {
|
||||
var pos [2]int16
|
||||
|
||||
j := index & 0x1
|
||||
index >>= 1
|
||||
i := index & 0x7
|
||||
pos[0] = i*5 + j*2 + 1
|
||||
|
||||
index >>= 3
|
||||
j = index & 0x3
|
||||
index >>= 2
|
||||
i = index & 0x7
|
||||
if j == 3 {
|
||||
pos[1] = i*5 + 4
|
||||
} else {
|
||||
pos[1] = i*5 + j
|
||||
}
|
||||
|
||||
for n := 0; n < cL_SUBFR; n++ {
|
||||
cod[n] = 0
|
||||
}
|
||||
for j := 0; j < 2; j++ {
|
||||
s := sign & 1
|
||||
cod[pos[j]] = s*16383 - 8192
|
||||
sign >>= 1
|
||||
}
|
||||
}
|
||||
|
||||
// decode3i40_14bits decodes the 3-pulse codebook for MR67. Mirrors
|
||||
// decode_3i40_14bits (d3_14pf.cpp).
|
||||
func decode3i40_14bits(sign, index int16, cod []int16) {
|
||||
var pos [3]int16
|
||||
|
||||
i := index & 0x7
|
||||
pos[0] = i * 5
|
||||
|
||||
index >>= 3
|
||||
j := index & 0x1
|
||||
index >>= 1
|
||||
i = index & 0x7
|
||||
pos[1] = i*5 + j*2 + 1
|
||||
|
||||
index >>= 3
|
||||
j = index & 0x1
|
||||
index >>= 1
|
||||
i = index & 0x7
|
||||
pos[2] = i*5 + j*2 + 2
|
||||
|
||||
for n := 0; n < cL_SUBFR; n++ {
|
||||
cod[n] = 0
|
||||
}
|
||||
for j := 0; j < 3; j++ {
|
||||
s := sign & 1
|
||||
cod[pos[j]] = s*16383 - 8192
|
||||
sign >>= 1
|
||||
}
|
||||
}
|
||||
|
||||
// decode4i40_17bits decodes the 4-pulse Gray-coded codebook for MR74/MR795.
|
||||
// Mirrors decode_4i40_17bits (d4_17pf.cpp).
|
||||
func decode4i40_17bits(sign, index int16, cod []int16) {
|
||||
var pos [4]int16
|
||||
|
||||
i := index & 0x7
|
||||
i = dgray[i]
|
||||
pos[0] = i * 5
|
||||
|
||||
index >>= 3
|
||||
i = index & 0x7
|
||||
i = dgray[i]
|
||||
pos[1] = i*5 + 1
|
||||
|
||||
index >>= 3
|
||||
i = index & 0x7
|
||||
i = dgray[i]
|
||||
pos[2] = i*5 + 2
|
||||
|
||||
index >>= 3
|
||||
j := index & 0x1
|
||||
index >>= 1
|
||||
i = index & 0x7
|
||||
i = dgray[i]
|
||||
pos[3] = i*5 + 3 + j
|
||||
|
||||
for n := 0; n < cL_SUBFR; n++ {
|
||||
cod[n] = 0
|
||||
}
|
||||
for j := 0; j < 4; j++ {
|
||||
s := sign & 0x1
|
||||
cod[pos[j]] = s*16383 - 8192
|
||||
sign >>= 1
|
||||
}
|
||||
}
|
||||
|
||||
// decompress10 expands one compressed 10x10x10 track index into three pulse
|
||||
// positions. Mirrors decompress10 (d8_31pf.cpp).
|
||||
func decompress10(MSBs, LSBs, index1, index2, index3 int16, posIndx []int16) {
|
||||
if MSBs > 124 {
|
||||
MSBs = 124
|
||||
}
|
||||
ia := mult(MSBs, 1311)
|
||||
ia = int16(int32(MSBs) - (L_mult(ia, 25) >> 1))
|
||||
ib := mult(ia, 6554)
|
||||
ib = ia - int16(L_mult(ib, 5)>>1)
|
||||
ib = shl(ib, 1)
|
||||
ic := LSBs - ((LSBs >> 2) << 2)
|
||||
posIndx[index1] = ib + (ic & 1)
|
||||
|
||||
ib = mult(ia, 6554)
|
||||
ib = shl(ib, 1)
|
||||
posIndx[index2] = ib + (ic >> 1)
|
||||
|
||||
ib = LSBs >> 2
|
||||
ic = mult(MSBs, 1311)
|
||||
ic = shl(ic, 1)
|
||||
posIndx[index3] = add(ib, ic)
|
||||
}
|
||||
|
||||
// decompressCode expands the eight compressed MR102 pulse indices into linear
|
||||
// signs and codeword positions. Mirrors decompress_code (d8_31pf.cpp).
|
||||
func decompressCode(indx, signIndx, posIndx []int16) {
|
||||
const nbTrack = 4
|
||||
for i := 0; i < nbTrack; i++ {
|
||||
signIndx[i] = indx[i]
|
||||
}
|
||||
|
||||
MSBs := indx[nbTrack] >> 3
|
||||
LSBs := indx[nbTrack] & 0x7
|
||||
decompress10(MSBs, LSBs, 0, 4, 1, posIndx)
|
||||
|
||||
MSBs = indx[nbTrack+1] >> 3
|
||||
LSBs = indx[nbTrack+1] & 0x7
|
||||
decompress10(MSBs, LSBs, 2, 6, 5, posIndx)
|
||||
|
||||
MSBs = indx[nbTrack+2] >> 2
|
||||
LSBs = indx[nbTrack+2] & 0x3
|
||||
ia := int16(L_mult(MSBs, 25) >> 1)
|
||||
ia += 12
|
||||
MSBs0_24 := ia >> 5
|
||||
|
||||
ia = mult(MSBs0_24, 6554)
|
||||
ia &= 1
|
||||
ib := mult(MSBs0_24, 6554)
|
||||
ib = MSBs0_24 - int16(L_mult(ib, 5)>>1)
|
||||
if ia == 1 {
|
||||
ib = 4 - ib
|
||||
}
|
||||
ib = shl(ib, 1)
|
||||
ia = LSBs & 0x1
|
||||
posIndx[3] = add(ib, ia)
|
||||
|
||||
ia = mult(MSBs0_24, 6554)
|
||||
ia = shl(ia, 1)
|
||||
posIndx[7] = ia + (LSBs >> 1)
|
||||
}
|
||||
|
||||
// dec8i40_31bits decodes the 8-pulse codebook for MR102. Mirrors
|
||||
// dec_8i40_31bits (d8_31pf.cpp).
|
||||
func dec8i40_31bits(index, cod []int16) {
|
||||
const nbTrack = 4
|
||||
var linearSigns [nbTrack]int16
|
||||
var linearCodewords [8]int16
|
||||
|
||||
for i := 0; i < cL_CODE; i++ {
|
||||
cod[i] = 0
|
||||
}
|
||||
decompressCode(index, linearSigns[:], linearCodewords[:])
|
||||
|
||||
for j := int16(0); j < nbTrack; j++ {
|
||||
pos1 := (linearCodewords[j] << 2) + j
|
||||
var sign int16
|
||||
if linearSigns[j] == 0 {
|
||||
sign = cPOS_CODE // +1.0
|
||||
} else {
|
||||
sign = -cPOS_CODE // -1.0
|
||||
}
|
||||
if pos1 < cL_SUBFR {
|
||||
cod[pos1] = sign
|
||||
}
|
||||
pos2 := (linearCodewords[j+4] << 2) + j
|
||||
if pos2 < pos1 {
|
||||
sign = negate(sign)
|
||||
}
|
||||
if pos2 < cL_SUBFR {
|
||||
cod[pos2] += sign
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// dec10i40_35bits decodes the 10-pulse Gray-coded codebook for MR122. Mirrors
|
||||
// dec_10i40_35bits (d1035pf.cpp).
|
||||
func dec10i40_35bits(index, cod []int16) {
|
||||
const nbTrack = 5
|
||||
for i := 0; i < cL_CODE; i++ {
|
||||
cod[i] = 0
|
||||
}
|
||||
for j := int16(0); j < nbTrack; j++ {
|
||||
tmp := index[j]
|
||||
i := tmp & 7
|
||||
i = dgray[i]
|
||||
i = i * 5
|
||||
pos1 := i + j
|
||||
|
||||
var sign int16
|
||||
if (tmp>>3)&1 == 0 {
|
||||
sign = 4096 // +1.0
|
||||
} else {
|
||||
sign = -4096 // -1.0
|
||||
}
|
||||
cod[pos1] = sign
|
||||
|
||||
i = index[j+5] & 7
|
||||
i = dgray[i]
|
||||
i = i * 5
|
||||
pos2 := i + j
|
||||
if pos2 < pos1 {
|
||||
sign = negate(sign)
|
||||
}
|
||||
cod[pos2] += sign
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package amrnb
|
||||
|
||||
// Gain dequantization, ported from opencore-amrnb d_gain_p.cpp, d_gain_c.cpp and
|
||||
// dec_gain.cpp. These turn the received gain indices into the per-subframe pitch
|
||||
// gain and fixed-codebook gain, driving the gc_pred energy predictor. dGainPitch
|
||||
// and dGainCode handle MR795/MR122; decGain handles the joint/scalar-VQ modes
|
||||
// (MR475 joint, MR515/MR59 low-rate, MR67/MR74/MR102 high-rate). Bit-exact with
|
||||
// the reference.
|
||||
|
||||
const cMR475_VQ_SIZE = 256
|
||||
|
||||
// dGainPitch returns the quantized pitch gain (Q14) for the given index.
|
||||
// Mirrors d_gain_pitch.
|
||||
func dGainPitch(mode int, index int16) int16 {
|
||||
gain := qua_gain_pitch[index]
|
||||
if mode == dMR122 {
|
||||
gain &^= 3 // clear 2 LSBits
|
||||
}
|
||||
return gain
|
||||
}
|
||||
|
||||
// dGainCode decodes the fixed-codebook gain for MR795/MR122 from the predicted
|
||||
// gain (gc_pred) and the quantized correction factor, then updates the
|
||||
// predictor. Mirrors d_gain_code.
|
||||
func (pred *gcPredState) dGainCode(mode int, index int16, code []int16) (gainCode int16) {
|
||||
r := pred.gcPred(mode, code)
|
||||
exp, frac := r.expGcode0, r.fracGcode0
|
||||
|
||||
index &= 31 // index < 32, avoid buffer overflow
|
||||
tblTmp := index + (index << 1)
|
||||
p := qua_gain_code[tblTmp:]
|
||||
|
||||
if mode == dMR122 {
|
||||
gcode0 := int16(pow2(exp, frac))
|
||||
gcode0 = shl(gcode0, 4)
|
||||
gainCode = shl(mult(gcode0, p[0]), 1)
|
||||
} else {
|
||||
gcode0 := int16(pow2(14, frac))
|
||||
lTmp := L_mult(p[0], gcode0)
|
||||
lTmp = L_shr(lTmp, sub(9, exp))
|
||||
gainCode = int16(lTmp >> 16) // Q1
|
||||
}
|
||||
|
||||
quaEnerMR122 := p[1]
|
||||
quaEner := p[2]
|
||||
pred.update(quaEnerMR122, quaEner)
|
||||
return gainCode
|
||||
}
|
||||
|
||||
// decGain decodes both the pitch gain and fixed-codebook gain for the
|
||||
// scalar/joint-VQ modes (all except MR795/MR122), updating the predictor.
|
||||
// evenSubfr selects the MR475 joint-gain half. Mirrors Dec_gain.
|
||||
func (pred *gcPredState) decGain(mode int, index int16, code []int16, evenSubfr int16) (gainPit, gainCod int16) {
|
||||
index = shl(index, 2)
|
||||
|
||||
var gCode, quaEnerMR122, quaEner int16
|
||||
|
||||
switch {
|
||||
case mode == dMR102 || mode == dMR74 || mode == dMR67:
|
||||
p := table_gain_highrates[index:]
|
||||
gainPit = p[0]
|
||||
gCode = p[1]
|
||||
quaEnerMR122 = p[2]
|
||||
quaEner = p[3]
|
||||
case mode == dMR475:
|
||||
index += (1 ^ evenSubfr) << 1 // evenSubfr is 0 or 1
|
||||
if index > int16(cMR475_VQ_SIZE*4-2) {
|
||||
index = int16(cMR475_VQ_SIZE*4 - 2)
|
||||
}
|
||||
p := table_gain_MR475[index:]
|
||||
gainPit = p[0]
|
||||
gCode = p[1]
|
||||
// Predictor update values are recomputed (not stored in the 4.75 table):
|
||||
// qua_ener_MR122 = log2(g), qua_ener = 20*log10(g)
|
||||
e, f := log2(int32(gCode)) // Log2(x Q12) = log2(x) + 12
|
||||
e -= 12
|
||||
t1 := shr_r(f, 5)
|
||||
t2 := shl(e, 10)
|
||||
quaEnerMR122 = add(t1, t2)
|
||||
lTmp := mpy32_16(e, f, 24660) // 24660 Q12 ~= 20*log10(2)
|
||||
lTmp = L_shl(lTmp, 13)
|
||||
quaEner = round_(lTmp)
|
||||
default: // MR515, MR59
|
||||
p := table_gain_lowrates[index:]
|
||||
gainPit = p[0]
|
||||
gCode = p[1]
|
||||
quaEnerMR122 = p[2]
|
||||
quaEner = p[3]
|
||||
}
|
||||
|
||||
r := pred.gcPred(mode, code)
|
||||
exp, frac := r.expGcode0, r.fracGcode0
|
||||
gcode0 := int16(pow2(14, frac))
|
||||
|
||||
lTmp := L_mult(gCode, gcode0)
|
||||
lTmp = L_shr(lTmp, 10-exp)
|
||||
gainCod = int16(lTmp >> 16)
|
||||
|
||||
pred.update(quaEnerMR122, quaEner)
|
||||
return gainPit, gainCod
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
package amrnb
|
||||
|
||||
// LSF dequantization, ported from opencore-amrnb d_plsf.cpp, d_plsf_3.cpp,
|
||||
// d_plsf_5.cpp and reorder.cpp. These reconstruct the line-spectral
|
||||
// frequencies from their transmitted codebook indices through a moving-average
|
||||
// predictor (state carried across frames), enforce a minimum LSF spacing, and
|
||||
// convert to the cosine (LSP) domain via lsfLsp. d_plsf_3 serves all modes
|
||||
// except 12.2 kbit/s; d_plsf_5 serves 12.2 kbit/s (two LSP sets per frame).
|
||||
|
||||
const (
|
||||
cLSF_GAP = 205 // minimum distance between adjacent LSFs (reorder)
|
||||
|
||||
cALPHA_3 = 29491 // 0.9 (d_plsf_3 bad-frame lean toward mean)
|
||||
cONE_ALPHA_3 = 3277 // 0.1
|
||||
cALPHA_5 = 31128 // ~0.95 (d_plsf_5 bad-frame)
|
||||
cONE_ALPHA_5 = 1639 // ~0.05
|
||||
|
||||
cLSP_PRED_FAC_MR122 = 21299 // 0.65 Q15, MR122 LSP prediction factor
|
||||
|
||||
cDICO1_SIZE = 256
|
||||
cDICO2_SIZE = 512
|
||||
cDICO3_SIZE = 512
|
||||
cMR515_3_SIZE = 128
|
||||
cMR795_1_SIZE = 512
|
||||
)
|
||||
|
||||
// dPlsfState holds the LSF predictor memory across frames. Mirrors D_plsfState.
|
||||
type dPlsfState struct {
|
||||
pastRQ [cM]int16 // past quantized prediction error, Q15
|
||||
pastLsfQ [cM]int16 // past dequantized LSFs, Q15
|
||||
}
|
||||
|
||||
// reset clears the LSF predictor: past residual to zero, past LSFs to the
|
||||
// 5-table mean. Mirrors D_plsf_reset.
|
||||
func (st *dPlsfState) reset() {
|
||||
for i := 0; i < cM; i++ {
|
||||
st.pastRQ[i] = 0
|
||||
}
|
||||
copy(st.pastLsfQ[:], mean_lsf_5[:cM])
|
||||
}
|
||||
|
||||
// reorderLsf enforces a minimum distance minDist between successive LSFs.
|
||||
// Mirrors Reorder_lsf (reorder.cpp).
|
||||
func reorderLsf(lsf []int16, minDist, n int16) {
|
||||
lsfMin := minDist
|
||||
for i := int16(0); i < n; i++ {
|
||||
if lsf[i] < lsfMin {
|
||||
lsf[i] = lsfMin
|
||||
lsfMin = lsfMin + minDist
|
||||
} else {
|
||||
lsfMin = lsf[i] + minDist
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// dPlsf3 decodes the 3-split LSF for the given mode from three indices into
|
||||
// lsp1q (length cM). bfi selects the bad-frame concealment path. Mirrors
|
||||
// D_plsf_3.
|
||||
func (st *dPlsfState) dPlsf3(mode int, bfi int16, indice []int16, lsp1q []int16) {
|
||||
var lsf1r, lsf1q [cM]int16
|
||||
|
||||
if bfi != 0 {
|
||||
for i := 0; i < cM; i++ {
|
||||
temp := mult(st.pastLsfQ[i], cALPHA_3)
|
||||
index := mult(mean_lsf_3[i], cONE_ALPHA_3)
|
||||
lsf1q[i] = add(index, temp)
|
||||
}
|
||||
if mode != dMRDTX {
|
||||
for i := 0; i < cM; i++ {
|
||||
temp := mult(st.pastRQ[i], pred_fac_3[i])
|
||||
temp = add(mean_lsf_3[i], temp)
|
||||
st.pastRQ[i] = sub(lsf1q[i], temp)
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < cM; i++ {
|
||||
temp := add(mean_lsf_3[i], st.pastRQ[i])
|
||||
st.pastRQ[i] = sub(lsf1q[i], temp)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var pCb1, pCb3 []int16
|
||||
var indexLimit1, indexLimit3 int16
|
||||
pCb2 := dico2_lsf_3
|
||||
indexLimit2 := int16((cDICO2_SIZE - 1) * 3)
|
||||
switch {
|
||||
case mode == dMR475 || mode == dMR515:
|
||||
pCb1, pCb3 = dico1_lsf_3, mr515_3_lsf
|
||||
indexLimit1, indexLimit3 = (cDICO1_SIZE-1)*3, (cMR515_3_SIZE-1)*4
|
||||
case mode == dMR795:
|
||||
pCb1, pCb3 = mr795_1_lsf, dico3_lsf_3
|
||||
indexLimit1, indexLimit3 = (cMR795_1_SIZE-1)*3, (cDICO3_SIZE-1)*4
|
||||
default: // MR59, MR67, MR74, MR102, MRDTX
|
||||
pCb1, pCb3 = dico1_lsf_3, dico3_lsf_3
|
||||
indexLimit1, indexLimit3 = (cDICO1_SIZE-1)*3, (cDICO3_SIZE-1)*4
|
||||
}
|
||||
|
||||
index := indice[0]
|
||||
temp := index + (index << 1)
|
||||
if temp > indexLimit1 {
|
||||
temp = indexLimit1
|
||||
}
|
||||
lsf1r[0] = pCb1[temp]
|
||||
lsf1r[1] = pCb1[temp+1]
|
||||
lsf1r[2] = pCb1[temp+2]
|
||||
|
||||
index = indice[1]
|
||||
if mode == dMR475 || mode == dMR515 {
|
||||
index <<= 1 // these modes use every second entry
|
||||
}
|
||||
temp = index + (index << 1)
|
||||
if temp > indexLimit2 {
|
||||
temp = indexLimit2
|
||||
}
|
||||
lsf1r[3] = pCb2[temp]
|
||||
lsf1r[4] = pCb2[temp+1]
|
||||
lsf1r[5] = pCb2[temp+2]
|
||||
|
||||
index = indice[2]
|
||||
temp = index << 2
|
||||
if temp > indexLimit3 {
|
||||
temp = indexLimit3
|
||||
}
|
||||
lsf1r[6] = pCb3[temp]
|
||||
lsf1r[7] = pCb3[temp+1]
|
||||
lsf1r[8] = pCb3[temp+2]
|
||||
lsf1r[9] = pCb3[temp+3]
|
||||
|
||||
if mode != dMRDTX {
|
||||
for i := 0; i < cM; i++ {
|
||||
temp = mult(st.pastRQ[i], pred_fac_3[i])
|
||||
temp = add(mean_lsf_3[i], temp)
|
||||
lsf1q[i] = add(lsf1r[i], temp)
|
||||
st.pastRQ[i] = lsf1r[i]
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < cM; i++ {
|
||||
temp = add(mean_lsf_3[i], st.pastRQ[i])
|
||||
lsf1q[i] = add(lsf1r[i], temp)
|
||||
st.pastRQ[i] = lsf1r[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reorderLsf(lsf1q[:], cLSF_GAP, cM)
|
||||
copy(st.pastLsfQ[:], lsf1q[:])
|
||||
lsfLsp(lsf1q[:], lsp1q, cM)
|
||||
}
|
||||
|
||||
// dPlsf5 decodes the 5-split LSF (MR122) from five indices into two LSP sets
|
||||
// lsp1q and lsp2q (each length cM). Mirrors D_plsf_5.
|
||||
func (st *dPlsfState) dPlsf5(bfi int16, indice []int16, lsp1q, lsp2q []int16) {
|
||||
var lsf1r, lsf2r, lsf1q, lsf2q [cM]int16
|
||||
|
||||
if bfi != 0 {
|
||||
for i := 0; i < cM; i++ {
|
||||
temp := int16((int32(st.pastLsfQ[i]) * cALPHA_5) >> 15)
|
||||
sign := int16((int32(mean_lsf_5[i]) * cONE_ALPHA_5) >> 15)
|
||||
lsf1q[i] = add(sign, temp)
|
||||
lsf2q[i] = lsf1q[i]
|
||||
temp = int16((int32(st.pastRQ[i]) * cLSP_PRED_FAC_MR122) >> 15)
|
||||
temp = add(mean_lsf_5[i], temp)
|
||||
st.pastRQ[i] = sub(lsf2q[i], temp)
|
||||
}
|
||||
} else {
|
||||
temp := shl(indice[0], 2)
|
||||
lsf1r[0] = dico1_lsf_5[temp]
|
||||
lsf1r[1] = dico1_lsf_5[temp+1]
|
||||
lsf2r[0] = dico1_lsf_5[temp+2]
|
||||
lsf2r[1] = dico1_lsf_5[temp+3]
|
||||
|
||||
temp = shl(indice[1], 2)
|
||||
lsf1r[2] = dico2_lsf_5[temp]
|
||||
lsf1r[3] = dico2_lsf_5[temp+1]
|
||||
lsf2r[2] = dico2_lsf_5[temp+2]
|
||||
lsf2r[3] = dico2_lsf_5[temp+3]
|
||||
|
||||
sign := indice[2] & 1
|
||||
var ii int16
|
||||
if indice[2] < 0 {
|
||||
ii = ^(^indice[2] >> 1)
|
||||
} else {
|
||||
ii = indice[2] >> 1
|
||||
}
|
||||
temp = shl(ii, 2)
|
||||
if sign == 0 {
|
||||
lsf1r[4] = dico3_lsf_5[temp]
|
||||
lsf1r[5] = dico3_lsf_5[temp+1]
|
||||
lsf2r[4] = dico3_lsf_5[temp+2]
|
||||
lsf2r[5] = dico3_lsf_5[temp+3]
|
||||
} else {
|
||||
lsf1r[4] = negate(dico3_lsf_5[temp])
|
||||
lsf1r[5] = negate(dico3_lsf_5[temp+1])
|
||||
lsf2r[4] = negate(dico3_lsf_5[temp+2])
|
||||
lsf2r[5] = negate(dico3_lsf_5[temp+3])
|
||||
}
|
||||
|
||||
temp = shl(indice[3], 2)
|
||||
lsf1r[6] = dico4_lsf_5[temp]
|
||||
lsf1r[7] = dico4_lsf_5[temp+1]
|
||||
lsf2r[6] = dico4_lsf_5[temp+2]
|
||||
lsf2r[7] = dico4_lsf_5[temp+3]
|
||||
|
||||
temp = shl(indice[4], 2)
|
||||
lsf1r[8] = dico5_lsf_5[temp]
|
||||
lsf1r[9] = dico5_lsf_5[temp+1]
|
||||
lsf2r[8] = dico5_lsf_5[temp+2]
|
||||
lsf2r[9] = dico5_lsf_5[temp+3]
|
||||
|
||||
for i := 0; i < cM; i++ {
|
||||
temp = mult(st.pastRQ[i], cLSP_PRED_FAC_MR122)
|
||||
temp = add(mean_lsf_5[i], temp)
|
||||
lsf1q[i] = add(lsf1r[i], temp)
|
||||
lsf2q[i] = add(lsf2r[i], temp)
|
||||
st.pastRQ[i] = lsf2r[i]
|
||||
}
|
||||
}
|
||||
|
||||
reorderLsf(lsf1q[:], cLSF_GAP, cM)
|
||||
reorderLsf(lsf2q[:], cLSF_GAP, cM)
|
||||
copy(st.pastLsfQ[:], lsf2q[:])
|
||||
lsfLsp(lsf1q[:], lsp1q, cM)
|
||||
lsfLsp(lsf2q[:], lsp2q, cM)
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
package amrnb
|
||||
|
||||
// AMR-NB decoder frame driver, ported from opencore-amrnb dec_amr.cpp
|
||||
// (Decoder_amr) and sp_dec.cpp (GSMFrameDecode). It orchestrates the
|
||||
// already-ported building blocks for one 20 ms frame: LSF dequantization and
|
||||
// LSP interpolation, then four subframes of pitch-lag decode, adaptive
|
||||
// codebook, fixed codebook with pitch sharpening, gain decode, excitation
|
||||
// assembly and LP synthesis; finally the formant post-filter and output
|
||||
// high-pass.
|
||||
//
|
||||
// This implements the active-speech (good-frame) path. Error concealment
|
||||
// (bad-frame / DTX), background-noise adaptation, the gain-averaging
|
||||
// (Cb_gain_average) and adaptive phase dispersion are not yet ported, so the
|
||||
// excitation is synthesized directly from the total excitation (equivalent to
|
||||
// phase dispersion disabled) and the code gain is used unmixed.
|
||||
|
||||
const (
|
||||
cSHARPMAX = 13017 // max pitch sharpening
|
||||
cExcOff = cPIT_MAX + cL_INTERPOL // 154: excitation history length
|
||||
cPIT_MIN_MR122 = 18
|
||||
)
|
||||
|
||||
// decoderStateDSP holds the persistent decoder synthesis state across frames.
|
||||
type decoderStateDSP struct {
|
||||
oldExc [cL_SUBFR + cPIT_MAX + cL_INTERPOL]int16 // excitation w/ history
|
||||
lspOld [cM]int16 // previous-frame LSPs
|
||||
memSyn [cM]int16 // synthesis filter memory
|
||||
sharp int16 // pitch sharpening (prev gain_pit)
|
||||
oldT0 int16 // previous integer pitch lag
|
||||
lsf dPlsfState // LSF predictor state
|
||||
pred gcPredState // gain predictor state
|
||||
pst postFilterState // formant post-filter state
|
||||
post postProcessState // output HP filter state
|
||||
}
|
||||
|
||||
func (st *decoderStateDSP) reset() {
|
||||
for i := range st.oldExc {
|
||||
st.oldExc[i] = 0
|
||||
}
|
||||
copy(st.lspOld[:], lsp_init_data[:cM])
|
||||
for i := range st.memSyn {
|
||||
st.memSyn[i] = 0
|
||||
}
|
||||
st.sharp = 0
|
||||
st.oldT0 = 40
|
||||
st.lsf.reset()
|
||||
st.pred.reset()
|
||||
st.pst.reset()
|
||||
st.post = postProcessState{}
|
||||
}
|
||||
|
||||
// sharpenCode applies pitch sharpening to the innovation: code[i] += pitSharp ·
|
||||
// code[i-T0] for i in [T0, L_SUBFR).
|
||||
func sharpenCode(code []int16, T0 int, pitSharp int16) {
|
||||
for i := T0; i < cL_SUBFR; i++ {
|
||||
code[i] = add(code[i], mult(code[i-T0], pitSharp))
|
||||
}
|
||||
}
|
||||
|
||||
// decodeAmr decodes one frame's parameters into 160 raw synthesis samples and
|
||||
// returns the four per-subframe LP coefficient sets for the post-filter.
|
||||
func (st *decoderStateDSP) decodeAmr(mode int, params []int16, synth []int16) []int16 {
|
||||
var lspMid, lspNew [cM]int16
|
||||
at := make([]int16, cNB_SUBFR*cMP1)
|
||||
|
||||
pi := 0
|
||||
if mode == dMR122 {
|
||||
st.lsf.dPlsf5(0, params[pi:pi+5], lspMid[:], lspNew[:])
|
||||
pi += 5
|
||||
intLpc1and3(st.lspOld[:], lspMid[:], lspNew[:], at)
|
||||
} else {
|
||||
st.lsf.dPlsf3(mode, 0, params[pi:pi+3], lspNew[:])
|
||||
pi += 3
|
||||
intLpc1to3(st.lspOld[:], lspNew[:], at)
|
||||
}
|
||||
copy(st.lspOld[:], lspNew[:])
|
||||
|
||||
var code [cL_SUBFR]int16
|
||||
exc := st.oldExc[cExcOff:] // current-subframe excitation window (40 samples)
|
||||
|
||||
azOff := 0
|
||||
subfrNr := -1
|
||||
evenSubfr := int16(0)
|
||||
var indexMR475 int16 // carried across the MR475 subframe pair
|
||||
|
||||
for iSubfr := 0; iSubfr < cL_FRAME; iSubfr += cL_SUBFR {
|
||||
subfrNr++
|
||||
evenSubfr = 1 - evenSubfr
|
||||
az := at[azOff:]
|
||||
|
||||
pitFlag := int16(iSubfr)
|
||||
if iSubfr == cL_FRAME_BY2 && mode != dMR475 && mode != dMR515 {
|
||||
pitFlag = 0
|
||||
}
|
||||
|
||||
// ---- pitch lag + adaptive codebook ----
|
||||
index := params[pi]
|
||||
pi++
|
||||
var T0, T0frac int16
|
||||
if mode != dMR122 {
|
||||
flag4 := int16(0)
|
||||
if mode == dMR475 || mode == dMR515 || mode == dMR59 || mode == dMR67 {
|
||||
flag4 = 1
|
||||
}
|
||||
deltaLow, deltaRange := int16(5), int16(9)
|
||||
if mode == dMR795 {
|
||||
deltaLow, deltaRange = 10, 19
|
||||
}
|
||||
t0min := sub(st.oldT0, deltaLow)
|
||||
if t0min < cPIT_MIN {
|
||||
t0min = cPIT_MIN
|
||||
}
|
||||
t0max := add(t0min, deltaRange)
|
||||
if t0max > cPIT_MAX {
|
||||
t0max = cPIT_MAX
|
||||
t0min = sub(t0max, deltaRange)
|
||||
}
|
||||
T0, T0frac = decLag3(index, t0min, t0max, pitFlag, st.oldT0, flag4)
|
||||
predLt(st.oldExc[:], cExcOff, T0, T0frac, cL_SUBFR, 1)
|
||||
} else {
|
||||
T0, T0frac = decLag6(index, cPIT_MIN_MR122, cPIT_MAX, pitFlag, st.oldT0)
|
||||
predLt(st.oldExc[:], cExcOff, T0, T0frac, cL_SUBFR, 0)
|
||||
}
|
||||
|
||||
// ---- fixed codebook + pitch sharpening ----
|
||||
var gainPit, gainCode int16
|
||||
switch mode {
|
||||
case dMR475, dMR515:
|
||||
posIdx := params[pi]
|
||||
pi++
|
||||
signs := params[pi]
|
||||
pi++
|
||||
decode2i40_9bits(int16(subfrNr), signs, posIdx, code[:])
|
||||
sharpenCode(code[:], int(T0), shl(st.sharp, 1))
|
||||
case dMR59:
|
||||
posIdx := params[pi]
|
||||
pi++
|
||||
signs := params[pi]
|
||||
pi++
|
||||
decode2i40_11bits(signs, posIdx, code[:])
|
||||
sharpenCode(code[:], int(T0), shl(st.sharp, 1))
|
||||
case dMR67:
|
||||
posIdx := params[pi]
|
||||
pi++
|
||||
signs := params[pi]
|
||||
pi++
|
||||
decode3i40_14bits(signs, posIdx, code[:])
|
||||
sharpenCode(code[:], int(T0), shl(st.sharp, 1))
|
||||
case dMR74, dMR795:
|
||||
posIdx := params[pi]
|
||||
pi++
|
||||
signs := params[pi]
|
||||
pi++
|
||||
decode4i40_17bits(signs, posIdx, code[:])
|
||||
sharpenCode(code[:], int(T0), shl(st.sharp, 1))
|
||||
case dMR102:
|
||||
dec8i40_31bits(params[pi:pi+7], code[:])
|
||||
pi += 7
|
||||
sharpenCode(code[:], int(T0), shl(st.sharp, 1))
|
||||
case dMR122:
|
||||
gpIdx := params[pi]
|
||||
pi++
|
||||
gainPit = dGainPitch(mode, gpIdx)
|
||||
dec10i40_35bits(params[pi:pi+10], code[:])
|
||||
pi += 10
|
||||
sharpenCode(code[:], int(T0), shl(gainPit, 1))
|
||||
}
|
||||
|
||||
// ---- gain decode ----
|
||||
switch mode {
|
||||
case dMR475:
|
||||
if evenSubfr != 0 {
|
||||
indexMR475 = params[pi]
|
||||
pi++
|
||||
}
|
||||
gainPit, gainCode = st.pred.decGain(mode, indexMR475, code[:], evenSubfr)
|
||||
case dMR515, dMR59, dMR67, dMR74, dMR102:
|
||||
idx := params[pi]
|
||||
pi++
|
||||
gainPit, gainCode = st.pred.decGain(mode, idx, code[:], evenSubfr)
|
||||
case dMR795:
|
||||
gpIdx := params[pi]
|
||||
pi++
|
||||
gainPit = dGainPitch(mode, gpIdx)
|
||||
gcIdx := params[pi]
|
||||
pi++
|
||||
gainCode = st.pred.dGainCode(mode, gcIdx, code[:])
|
||||
case dMR122:
|
||||
gcIdx := params[pi]
|
||||
pi++
|
||||
gainCode = st.pred.dGainCode(mode, gcIdx, code[:])
|
||||
}
|
||||
|
||||
// store pitch sharpening for next subframe (not in MR475 even subframe)
|
||||
if mode != dMR475 || evenSubfr == 0 {
|
||||
st.sharp = gainPit
|
||||
if st.sharp > cSHARPMAX {
|
||||
st.sharp = cSHARPMAX
|
||||
}
|
||||
}
|
||||
|
||||
// ---- total excitation: gain_pit·adaptive + gain_code·code ----
|
||||
var pitchFac, tmpShift int16
|
||||
if mode <= dMR102 {
|
||||
pitchFac = gainPit
|
||||
tmpShift = 1
|
||||
} else {
|
||||
pitchFac = shr(gainPit, 1)
|
||||
tmpShift = 2
|
||||
}
|
||||
for i := 0; i < cL_SUBFR; i++ {
|
||||
L := L_mult(exc[i], pitchFac)
|
||||
L = L_mac(L, code[i], gainCode)
|
||||
L = L_shl(L, tmpShift)
|
||||
exc[i] = round_(L)
|
||||
}
|
||||
|
||||
// ---- LP synthesis ----
|
||||
synFilt(az, exc[:cL_SUBFR], synth[iSubfr:iSubfr+cL_SUBFR], cL_SUBFR, st.memSyn[:], false)
|
||||
copy(st.memSyn[:], synth[iSubfr+cL_SUBFR-cM:iSubfr+cL_SUBFR])
|
||||
|
||||
// slide the excitation buffer left by one subframe
|
||||
copy(st.oldExc[:cExcOff], st.oldExc[cL_SUBFR:cL_SUBFR+cExcOff])
|
||||
|
||||
st.oldT0 = T0
|
||||
azOff += cMP1
|
||||
}
|
||||
|
||||
return at
|
||||
}
|
||||
|
||||
// decodeSpeechFrame decodes one good speech frame end-to-end into 160 PCM
|
||||
// samples: parameter decode, post-filter, output high-pass, and the 13-bit
|
||||
// output truncation. Mirrors GSMFrameDecode for the speech path.
|
||||
func (st *decoderStateDSP) decodeSpeechFrame(mode int, params []int16, synth []int16) {
|
||||
az := st.decodeAmr(mode, params, synth)
|
||||
st.pst.postFilter(mode, synth, az)
|
||||
st.post.process(synth, cL_FRAME)
|
||||
for i := 0; i < cL_FRAME; i++ {
|
||||
synth[i] &^= 7 // truncate to 13 bits
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package amrnb
|
||||
|
||||
// Encoder-side bit serialization, ported from opencore-amrnb prm2bits.cpp
|
||||
// (Int2bin/Prm2bits) and the ETS->IETF reordering in ets_to_wmf.cpp
|
||||
// (ets_to_ietf). The chain is: parameter array -> ETS serial bits (each
|
||||
// parameter expanded MSB-first to its bitno width) -> IETF storage bytes (the
|
||||
// ETS bits permuted by reorderBits and packed MSB-first). The leading ToC byte
|
||||
// is added by the payload layer, not here.
|
||||
|
||||
// int2bin writes the low nBits of value into bits[0:nBits], MSB first
|
||||
// (bits[0] is the most significant bit). Mirrors Int2bin.
|
||||
func int2bin(value int16, nBits int, bits []int16) {
|
||||
for i := nBits - 1; i >= 0; i-- {
|
||||
bits[i] = value & 1
|
||||
value >>= 1
|
||||
}
|
||||
}
|
||||
|
||||
// prm2bits expands the encoder parameter array prm into the ETS serial bit
|
||||
// array for the given speech mode (length modeBits[mode]). Mirrors Prm2bits.
|
||||
func prm2bits(mode Mode, prm []int16) []int16 {
|
||||
bn := bitno[mode]
|
||||
ets := make([]int16, modeBits[mode])
|
||||
pos := 0
|
||||
for i, w := range bn {
|
||||
int2bin(prm[i], int(w), ets[pos:])
|
||||
pos += int(w)
|
||||
}
|
||||
return ets
|
||||
}
|
||||
|
||||
// etsToIetf permutes the ETS serial bits into IETF storage order via
|
||||
// reorderBits[mode] and packs them MSB-first into bytes. Mirrors the speech
|
||||
// branch of ets_to_ietf (without the ToC byte).
|
||||
func etsToIetf(mode Mode, ets []int16) []byte {
|
||||
nb := modeBits[mode]
|
||||
ro := reorderBits[mode]
|
||||
out := make([]byte, (nb+7)/8)
|
||||
for k := 0; k < nb; k++ {
|
||||
bit := ets[ro[k]] & 1
|
||||
out[k>>3] |= byte(bit) << uint(7-(k&7))
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// packFrame serializes a mode's encoder parameters into the RFC 4867 speech
|
||||
// payload bytes (IETF storage order), the inverse of mimeUnsort.
|
||||
func packFrame(prm []int16, mode Mode) []byte {
|
||||
return etsToIetf(mode, prm2bits(mode, prm))
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package amrnb
|
||||
|
||||
// 10-pulse algebraic codebook search (35 bits, MR122), ported from
|
||||
// opencore-amrnb c1035pf.cpp. Reuses search10and8i40 (10 pulses, step 5), then
|
||||
// builds the codeword (±4096 pulses) and Gray-encodes the per-track position
|
||||
// indices (q_p). The exact encoder counterpart of dec10i40_35bits. Bit-exact
|
||||
// with the reference.
|
||||
|
||||
// build10Code assembles the 10-pulse innovation cod, filtered code y, and the
|
||||
// raw per-track position+sign indices (with the same-track ordering/swap logic
|
||||
// that the decoder inverts). Mirrors build_code (c1035pf.cpp).
|
||||
func build10Code(codvec, sign, cod, h, y, indx []int16) {
|
||||
const L = cL_CODE
|
||||
for i := 0; i < L; i++ {
|
||||
cod[i] = 0
|
||||
}
|
||||
for t := 0; t < 5; t++ {
|
||||
indx[t] = -1
|
||||
}
|
||||
|
||||
var sgn [10]int16
|
||||
for k := 0; k < 10; k++ {
|
||||
i := codvec[k]
|
||||
index := int16((int32(i) * 6554) >> 15)
|
||||
track := i - (index + (index << 2)) // i - index*5
|
||||
|
||||
if sign[i] > 0 {
|
||||
cod[i] += 4096
|
||||
sgn[k] = 8192
|
||||
} else {
|
||||
cod[i] -= 4096
|
||||
sgn[k] = -8192
|
||||
index += 8
|
||||
}
|
||||
|
||||
temp := indx[track]
|
||||
switch {
|
||||
case temp < 0:
|
||||
indx[track] = index
|
||||
case (index^temp)&8 == 0:
|
||||
if temp <= index {
|
||||
indx[track+5] = index
|
||||
} else {
|
||||
indx[track+5] = temp
|
||||
indx[track] = index
|
||||
}
|
||||
default:
|
||||
if (temp & 7) <= (index & 7) {
|
||||
indx[track+5] = temp
|
||||
indx[track] = index
|
||||
} else {
|
||||
indx[track+5] = index
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < L; i++ {
|
||||
var s int32
|
||||
for k := 0; k < 10; k++ {
|
||||
ci := int(codvec[k])
|
||||
var hv int16
|
||||
if i-ci >= 0 {
|
||||
hv = h[i-ci]
|
||||
}
|
||||
s += (int32(hv) * int32(sgn[k])) >> 7
|
||||
}
|
||||
y[i] = int16((s + 0x80) >> 8)
|
||||
}
|
||||
}
|
||||
|
||||
// code10i40_35bits runs the full MR122 10-pulse search, writing the innovation
|
||||
// cod, filtered code y, and the 10-value Gray-coded index. Mirrors
|
||||
// code_10i40_35bits.
|
||||
func code10i40_35bits(x, cn, h, cod, y, indx []int16) {
|
||||
var dn, sign [cL_CODE]int16
|
||||
var rr [cL_CODE * cL_CODE]int16
|
||||
var ipos, codvec [10]int16
|
||||
var posMax [5]int16
|
||||
|
||||
corHX(h, x, dn[:], 2)
|
||||
setSign12k2(dn[:], cn, sign[:], posMax[:], 5, ipos[:], 5)
|
||||
corH(h, sign[:], rr[:])
|
||||
search10and8i40(10, 5, 5, dn[:], rr[:], ipos[:], posMax[:], codvec[:])
|
||||
build10Code(codvec[:], sign[:], cod, h, y, indx)
|
||||
|
||||
// q_p: Gray-encode each track's position index (keeping the sign bit for the
|
||||
// first five).
|
||||
for n := 0; n < 10; n++ {
|
||||
tmp := indx[n]
|
||||
if n < 5 {
|
||||
indx[n] = (tmp & 0x8) | gray[tmp&0x7]
|
||||
} else {
|
||||
indx[n] = gray[tmp&0x7]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
package amrnb
|
||||
|
||||
// 2-pulse algebraic codebook search (9 bits, MR475/MR515), ported from
|
||||
// opencore-amrnb c2_9pf.cpp. code2i40_9bits sharpens the impulse response with
|
||||
// the pitch gain, builds the correlation gradient (corHX) and the rr criterion
|
||||
// matrix (corH), exhaustively searches the two pulse positions maximizing
|
||||
// ps²/energy (search2i40), then assembles the innovation vector, its filtered
|
||||
// version, and the codebook index (build2Code). The exact encoder counterpart
|
||||
// of the decoder's decode2i40_9bits. Bit-exact with the reference.
|
||||
|
||||
// per-subframe track table used to encode the pulse track-pair (c2_9pf.cpp).
|
||||
var trackTable = [20]int16{
|
||||
0, 1, 0, 1, -1, // subframe 1
|
||||
0, -1, 1, 0, 1, // subframe 2
|
||||
0, 1, 0, -1, 1, // subframe 3
|
||||
0, 1, -1, 0, 1, // subframe 4
|
||||
}
|
||||
|
||||
// search2i40 finds the two pulse positions (one per track of a track pair) that
|
||||
// maximize the codebook criterion ps²/energy. Mirrors search_2i40.
|
||||
func search2i40(subNr int16, dn, rr, codvec []int16) {
|
||||
const L = cL_CODE
|
||||
var ipos [2]int16
|
||||
psk := int16(-1)
|
||||
alpk := int16(1)
|
||||
codvec[0] = 0
|
||||
codvec[1] = 1
|
||||
|
||||
for track1 := int16(0); track1 < 2; track1++ {
|
||||
i := (subNr << 1) + (track1 << 3)
|
||||
ipos[0] = startPos[i]
|
||||
ipos[1] = startPos[i+1]
|
||||
|
||||
for i0 := ipos[0]; i0 < L; i0 += cSTEP {
|
||||
ps0 := dn[i0]
|
||||
alp0 := int32(rr[int(i0)*L+int(i0)]) << 14
|
||||
|
||||
sq := int16(-1)
|
||||
alp := int16(1)
|
||||
ix := ipos[1]
|
||||
|
||||
for i1 := ipos[1]; i1 < L; i1 += cSTEP {
|
||||
ps1 := ps0 + dn[i1]
|
||||
alp1 := alp0 + (int32(rr[int(i1)*L+int(i1)]) << 14)
|
||||
alp1 += int32(rr[int(i0)*L+int(i1)]) << 15
|
||||
sq1 := int16((int32(ps1) * int32(ps1)) >> 15)
|
||||
alp16 := int16((alp1 + 0x8000) >> 16)
|
||||
s := (int32(alp)*int32(sq1))<<1 - (int32(sq)*int32(alp16))<<1
|
||||
if s > 0 {
|
||||
sq = sq1
|
||||
alp = alp16
|
||||
ix = i1
|
||||
}
|
||||
}
|
||||
|
||||
s := (int32(alpk)*int32(sq))<<1 - (int32(psk)*int32(alp))<<1
|
||||
if s > 0 {
|
||||
psk = sq
|
||||
alpk = alp
|
||||
codvec[0] = i0
|
||||
codvec[1] = ix
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// build2Code assembles the innovation vector cod (two ±8191/∓8192 pulses), its
|
||||
// filtered version y, the pulse signs, and the codebook index. Mirrors
|
||||
// build_code (c2_9pf.cpp).
|
||||
func build2Code(subNr int16, codvec, dnSign, cod, h, y []int16) (indx, sign int16) {
|
||||
const L = cL_CODE
|
||||
ptBase := int(subNr) + (int(subNr) << 2) // subNr*5
|
||||
for i := 0; i < L; i++ {
|
||||
cod[i] = 0
|
||||
}
|
||||
|
||||
var sgn [2]int16
|
||||
rsign := int16(0)
|
||||
for k := 0; k < 2; k++ {
|
||||
i := codvec[k]
|
||||
j := dnSign[i]
|
||||
index := int16((int32(i) * 6554) >> 15) // pos/5
|
||||
track := i - 5*index
|
||||
first := trackTable[ptBase+int(track)]
|
||||
if k == 0 {
|
||||
track = 0
|
||||
if first != 0 {
|
||||
index += 64
|
||||
}
|
||||
} else {
|
||||
track = 1
|
||||
index <<= 3
|
||||
}
|
||||
if j > 0 {
|
||||
cod[i] = 8191
|
||||
sgn[k] = 32767
|
||||
rsign += 1 << uint(track)
|
||||
} else {
|
||||
cod[i] = -8192
|
||||
sgn[k] = -32768
|
||||
}
|
||||
indx += index
|
||||
}
|
||||
sign = rsign
|
||||
|
||||
c0, c1 := int(codvec[0]), int(codvec[1])
|
||||
for i := 0; i < L; i++ {
|
||||
var h0, h1 int16
|
||||
if i-c0 >= 0 {
|
||||
h0 = h[i-c0]
|
||||
}
|
||||
if i-c1 >= 0 {
|
||||
h1 = h[i-c1]
|
||||
}
|
||||
s := L_mult(h0, sgn[0])
|
||||
s = L_mac(s, h1, sgn[1])
|
||||
y[i] = round_(s)
|
||||
}
|
||||
return indx, sign
|
||||
}
|
||||
|
||||
// code2i40_9bits runs the full 2-pulse search for one subframe, returning the
|
||||
// codebook index and pulse signs and writing the innovation code and its
|
||||
// filtered version y. h is sharpened in place by the pitch gain. Mirrors
|
||||
// code_2i40_9bits.
|
||||
func code2i40_9bits(subNr int16, x, h []int16, T0, pitchSharp int16, code, y []int16) (index, sign int16) {
|
||||
sharp := shl(pitchSharp, 1)
|
||||
if T0 < cL_CODE {
|
||||
for i := T0; i < cL_CODE; i++ {
|
||||
h[i] = add(h[i], mult(h[i-T0], sharp))
|
||||
}
|
||||
}
|
||||
|
||||
var dn, dn2, dnSign [cL_CODE]int16
|
||||
var rr [cL_CODE * cL_CODE]int16
|
||||
var codvec [2]int16
|
||||
|
||||
corHX(h, x, dn[:], 1)
|
||||
setSign(dn[:], dnSign[:], dn2[:], 8)
|
||||
corH(h, dnSign[:], rr[:])
|
||||
search2i40(subNr, dn[:], rr[:], codvec[:])
|
||||
index, sign = build2Code(subNr, codvec[:], dnSign[:], code, h, y)
|
||||
|
||||
if T0 < cL_CODE {
|
||||
for i := T0; i < cL_CODE; i++ {
|
||||
code[i] = add(code[i], mult(code[i-T0], sharp))
|
||||
}
|
||||
}
|
||||
return index, sign
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
package amrnb
|
||||
|
||||
// 2-pulse algebraic codebook search (11 bits, MR59), ported from opencore-amrnb
|
||||
// c2_11pf.cpp. Like c2_9pf but with a wider track structure (2×4 track pairs)
|
||||
// and its own index encoding. Reuses corHX/setSign/corH. The exact encoder
|
||||
// counterpart of decode2i40_11bits. Bit-exact with the reference.
|
||||
|
||||
var startPos1 = [2]int16{1, 3}
|
||||
var startPos2 = [4]int16{0, 1, 2, 4}
|
||||
|
||||
// search2i40_11 finds the two pulse positions maximizing ps²/energy across the
|
||||
// 2×4 track pairs. Mirrors search_2i40 (c2_11pf.cpp).
|
||||
func search2i40_11(dn, rr, codvec []int16) {
|
||||
const L = cL_CODE
|
||||
var ipos [2]int16
|
||||
psk := int16(-1)
|
||||
alpk := int16(1)
|
||||
codvec[0] = 0
|
||||
codvec[1] = 1
|
||||
|
||||
for track1 := 0; track1 < 2; track1++ {
|
||||
for track2 := 0; track2 < 4; track2++ {
|
||||
ipos[0] = startPos1[track1]
|
||||
ipos[1] = startPos2[track2]
|
||||
|
||||
for i0 := ipos[0]; i0 < L; i0 += cSTEP {
|
||||
ps0 := dn[i0]
|
||||
alp0 := int32(rr[int(i0)*L+int(i0)]) << 14
|
||||
|
||||
sq := int16(-1)
|
||||
alp := int16(1)
|
||||
ix := ipos[1]
|
||||
|
||||
for i1 := ipos[1]; i1 < L; i1 += cSTEP {
|
||||
ps1 := add(ps0, dn[i1])
|
||||
alp1 := alp0 + (int32(rr[int(i1)*L+int(i1)]) << 14)
|
||||
alp1 += int32(rr[int(i0)*L+int(i1)]) << 15
|
||||
sq1 := int16((int32(ps1) * int32(ps1)) >> 15)
|
||||
alp16 := int16((alp1 + 0x8000) >> 16)
|
||||
s := (int32(alp)*int32(sq1))<<1 - (int32(sq)*int32(alp16))<<1
|
||||
if s > 0 {
|
||||
sq = sq1
|
||||
alp = alp16
|
||||
ix = i1
|
||||
}
|
||||
}
|
||||
|
||||
s := (int32(alpk)*int32(sq))<<1 - (int32(psk)*int32(alp))<<1
|
||||
if s > 0 {
|
||||
psk = sq
|
||||
alpk = alp
|
||||
codvec[0] = i0
|
||||
codvec[1] = ix
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// build2Code11 assembles the innovation, filtered code, signs and the 11-bit
|
||||
// index. Mirrors build_code (c2_11pf.cpp).
|
||||
func build2Code11(codvec, dnSign, cod, h, y []int16) (indx, sign int16) {
|
||||
const L = cL_CODE
|
||||
for i := 0; i < L; i++ {
|
||||
cod[i] = 0
|
||||
}
|
||||
|
||||
var sgn [2]int16
|
||||
rsign := int16(0)
|
||||
for k := 0; k < 2; k++ {
|
||||
i := codvec[k]
|
||||
j := dnSign[i]
|
||||
index := int16((int32(i) * 6554) >> 15)
|
||||
tw := (index << 3) + (index << 1) // index*10
|
||||
tw >>= 1 // index*5
|
||||
track := i - tw // i % 5
|
||||
|
||||
switch track {
|
||||
case 0:
|
||||
track = 1
|
||||
index <<= 6
|
||||
case 1:
|
||||
if k == 0 {
|
||||
track = 0
|
||||
index <<= 1
|
||||
} else {
|
||||
track = 1
|
||||
index = (index << 6) + 16
|
||||
}
|
||||
case 2:
|
||||
track = 1
|
||||
index = (index << 6) + 32
|
||||
case 3:
|
||||
track = 0
|
||||
index = (index << 1) + 1
|
||||
case 4:
|
||||
track = 1
|
||||
index = (index << 6) + 48
|
||||
}
|
||||
|
||||
if j > 0 {
|
||||
cod[i] = 8191
|
||||
sgn[k] = 32767
|
||||
rsign = add(rsign, shl(1, track))
|
||||
} else {
|
||||
cod[i] = -8192
|
||||
sgn[k] = -32768
|
||||
}
|
||||
indx = add(indx, index)
|
||||
}
|
||||
sign = rsign
|
||||
|
||||
c0, c1 := int(codvec[0]), int(codvec[1])
|
||||
for i := 0; i < L; i++ {
|
||||
var h0, h1 int16
|
||||
if i-c0 >= 0 {
|
||||
h0 = h[i-c0]
|
||||
}
|
||||
if i-c1 >= 0 {
|
||||
h1 = h[i-c1]
|
||||
}
|
||||
s := L_mult(h0, sgn[0])
|
||||
s = L_mac(s, h1, sgn[1])
|
||||
y[i] = round_(s)
|
||||
}
|
||||
return indx, sign
|
||||
}
|
||||
|
||||
// code2i40_11bits runs the full MR59 2-pulse search. Mirrors code_2i40_11bits.
|
||||
func code2i40_11bits(x, h []int16, T0, pitchSharp int16, code, y []int16) (index, sign int16) {
|
||||
sharp := shl(pitchSharp, 1)
|
||||
if T0 < cL_CODE {
|
||||
for i := T0; i < cL_CODE; i++ {
|
||||
h[i] = add(h[i], mult(h[i-T0], sharp))
|
||||
}
|
||||
}
|
||||
|
||||
var dn, dn2, dnSign [cL_CODE]int16
|
||||
var rr [cL_CODE * cL_CODE]int16
|
||||
var codvec [2]int16
|
||||
|
||||
corHX(h, x, dn[:], 1)
|
||||
setSign(dn[:], dnSign[:], dn2[:], 8)
|
||||
corH(h, dnSign[:], rr[:])
|
||||
search2i40_11(dn[:], rr[:], codvec[:])
|
||||
index, sign = build2Code11(codvec[:], dnSign[:], code, h, y)
|
||||
|
||||
if T0 < cL_CODE {
|
||||
for i := T0; i < cL_CODE; i++ {
|
||||
code[i] = add(code[i], mult(code[i-T0], sharp))
|
||||
}
|
||||
}
|
||||
return index, sign
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
package amrnb
|
||||
|
||||
// 3-pulse algebraic codebook search (14 bits, MR67), ported from opencore-amrnb
|
||||
// c3_14pf.cpp. A depth-first search: the first pulse ranges only over the
|
||||
// pruned candidate positions (dn2), then nested searches place the 2nd and 3rd
|
||||
// pulses; the track triple is cyclically rotated so each track gets the pruned
|
||||
// role. The exact encoder counterpart of decode3i40_14bits. Bit-exact with the
|
||||
// reference.
|
||||
|
||||
// search3i40 places three pulses maximizing the codebook criterion. Mirrors
|
||||
// search_3i40 (c3_14pf.cpp).
|
||||
func search3i40(dn, dn2, rr, codvec []int16) {
|
||||
const L = cL_CODE
|
||||
var ipos [3]int16
|
||||
psk := int16(-1)
|
||||
alpk := int16(1)
|
||||
codvec[0], codvec[1], codvec[2] = 0, 1, 2
|
||||
|
||||
for track1 := int16(1); track1 < 4; track1 += 2 {
|
||||
for track2 := int16(2); track2 < 5; track2 += 2 {
|
||||
ipos[0], ipos[1], ipos[2] = 0, track1, track2
|
||||
|
||||
for rot := 0; rot < 3; rot++ {
|
||||
for i0 := ipos[0]; i0 < L; i0 += cSTEP {
|
||||
if dn2[i0] < 0 {
|
||||
continue
|
||||
}
|
||||
ps0 := dn[i0]
|
||||
alp0 := int32(rr[int(i0)*L+int(i0)]) << 14
|
||||
|
||||
sq := int16(-1)
|
||||
alp := int16(1)
|
||||
ps := int16(0)
|
||||
ix := ipos[1]
|
||||
for i1 := ipos[1]; i1 < L; i1 += cSTEP {
|
||||
ps1 := ps0 + dn[i1]
|
||||
alp1 := alp0 + (int32(rr[int(i1)*L+int(i1)]) << 14)
|
||||
alp1 += int32(rr[int(i0)*L+int(i1)]) << 15
|
||||
sq1 := int16((int32(ps1) * int32(ps1)) >> 15)
|
||||
alp16 := int16((alp1 + 0x8000) >> 16)
|
||||
s := (int32(alp)*int32(sq1))<<1 - (int32(sq)*int32(alp16))<<1
|
||||
if s > 0 {
|
||||
sq = sq1
|
||||
ps = ps1
|
||||
alp = alp16
|
||||
ix = i1
|
||||
}
|
||||
}
|
||||
i1 := ix
|
||||
|
||||
ps0 = ps
|
||||
alp0 = int32(alp) << 14
|
||||
sq = -1
|
||||
alp = 1
|
||||
ps = 0
|
||||
ix = ipos[2]
|
||||
for i2 := ipos[2]; i2 < L; i2 += cSTEP {
|
||||
ps1 := ps0 + dn[i2]
|
||||
alp1 := alp0 + (int32(rr[int(i2)*L+int(i2)]) << 12)
|
||||
alp1 += int32(rr[int(i1)*L+int(i2)]) << 13
|
||||
alp1 += int32(rr[int(i0)*L+int(i2)]) << 13
|
||||
sq1 := int16((int32(ps1) * int32(ps1)) >> 15)
|
||||
alp16 := int16((alp1 + 0x8000) >> 16)
|
||||
s := (int32(alp)*int32(sq1))<<1 - (int32(sq)*int32(alp16))<<1
|
||||
if s > 0 {
|
||||
sq = sq1
|
||||
ps = ps1
|
||||
alp = alp16
|
||||
ix = i2
|
||||
}
|
||||
}
|
||||
i2 := ix
|
||||
|
||||
s := L_msu(L_mult(alpk, sq), psk, alp)
|
||||
if s > 0 {
|
||||
psk = sq
|
||||
alpk = alp
|
||||
codvec[0], codvec[1], codvec[2] = i0, i1, i2
|
||||
}
|
||||
}
|
||||
pos := ipos[2]
|
||||
ipos[2] = ipos[1]
|
||||
ipos[1] = ipos[0]
|
||||
ipos[0] = pos
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// build3Code assembles the 3-pulse innovation, filtered code, signs and 14-bit
|
||||
// index. Mirrors build_code (c3_14pf.cpp).
|
||||
func build3Code(codvec, dnSign, cod, h, y []int16) (indx, sign int16) {
|
||||
const L = cL_CODE
|
||||
for i := 0; i < L; i++ {
|
||||
cod[i] = 0
|
||||
}
|
||||
|
||||
var sgn [3]int16
|
||||
rsign := int16(0)
|
||||
for k := 0; k < 3; k++ {
|
||||
i := codvec[k]
|
||||
j := dnSign[i]
|
||||
index := int16((int32(i) * 6554) >> 15)
|
||||
track := i - index*5
|
||||
switch track {
|
||||
case 1:
|
||||
index <<= 4
|
||||
case 2:
|
||||
track = 2
|
||||
index <<= 8
|
||||
case 3:
|
||||
track = 1
|
||||
index = (index << 4) + 8
|
||||
case 4:
|
||||
track = 2
|
||||
index = (index << 8) + 128
|
||||
}
|
||||
if j > 0 {
|
||||
cod[i] = 8191
|
||||
sgn[k] = 32767
|
||||
track = 1 << uint(track)
|
||||
rsign += track
|
||||
} else {
|
||||
cod[i] = -8192
|
||||
sgn[k] = -32768
|
||||
}
|
||||
indx += index
|
||||
}
|
||||
sign = rsign
|
||||
|
||||
c0, c1, c2 := int(codvec[0]), int(codvec[1]), int(codvec[2])
|
||||
for i := 0; i < L; i++ {
|
||||
var h0, h1, h2 int16
|
||||
if i-c0 >= 0 {
|
||||
h0 = h[i-c0]
|
||||
}
|
||||
if i-c1 >= 0 {
|
||||
h1 = h[i-c1]
|
||||
}
|
||||
if i-c2 >= 0 {
|
||||
h2 = h[i-c2]
|
||||
}
|
||||
s := L_mac(L_mac(L_mult(h0, sgn[0]), h1, sgn[1]), h2, sgn[2])
|
||||
y[i] = round_(s)
|
||||
}
|
||||
return indx, sign
|
||||
}
|
||||
|
||||
// code3i40_14bits runs the full MR67 3-pulse search. Mirrors code_3i40_14bits.
|
||||
func code3i40_14bits(x, h []int16, T0, pitchSharp int16, code, y []int16) (index, sign int16) {
|
||||
sharp := shl(pitchSharp, 1)
|
||||
if T0 < cL_CODE {
|
||||
for i := T0; i < cL_CODE; i++ {
|
||||
h[i] = add(h[i], mult(h[i-T0], sharp))
|
||||
}
|
||||
}
|
||||
|
||||
var dn, dn2, dnSign [cL_CODE]int16
|
||||
var rr [cL_CODE * cL_CODE]int16
|
||||
var codvec [3]int16
|
||||
|
||||
corHX(h, x, dn[:], 1)
|
||||
setSign(dn[:], dnSign[:], dn2[:], 6)
|
||||
corH(h, dnSign[:], rr[:])
|
||||
search3i40(dn[:], dn2[:], rr[:], codvec[:])
|
||||
index, sign = build3Code(codvec[:], dnSign[:], code, h, y)
|
||||
|
||||
if T0 < cL_CODE {
|
||||
for i := T0; i < cL_CODE; i++ {
|
||||
code[i] = add(code[i], mult(code[i-T0], sharp))
|
||||
}
|
||||
}
|
||||
return index, sign
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
package amrnb
|
||||
|
||||
// 4-pulse algebraic codebook search (17 bits, MR74/MR795), ported from
|
||||
// opencore-amrnb c4_17pf.cpp. A depth-first search over four pulses with dn2
|
||||
// pruning of the first pulse and cyclic track rotation; the index is Gray-coded
|
||||
// per position. The exact encoder counterpart of decode4i40_17bits. Bit-exact
|
||||
// with the reference.
|
||||
|
||||
// search4i40 places four pulses maximizing the codebook criterion. Mirrors
|
||||
// search_4i40 (c4_17pf.cpp).
|
||||
func search4i40(dn, dn2, rr, codvec []int16) {
|
||||
const L = cL_CODE
|
||||
var ipos [4]int16
|
||||
psk := int16(-1)
|
||||
alpk := int16(1)
|
||||
codvec[0], codvec[1], codvec[2], codvec[3] = 0, 1, 2, 3
|
||||
|
||||
for track := int16(3); track < 5; track++ {
|
||||
ipos[0], ipos[1], ipos[2], ipos[3] = 0, 1, 2, track
|
||||
|
||||
for rot := 0; rot < 4; rot++ {
|
||||
for i0 := ipos[0]; i0 < L; i0 += cSTEP {
|
||||
if dn2[i0] < 0 {
|
||||
continue
|
||||
}
|
||||
ps0 := dn[i0]
|
||||
alp0 := int32(rr[int(i0)*L+int(i0)]) << 14
|
||||
|
||||
sq := int16(-1)
|
||||
alp := int16(1)
|
||||
ps := int16(0)
|
||||
ix := ipos[1]
|
||||
for i1 := ipos[1]; i1 < L; i1 += cSTEP {
|
||||
ps1 := ps0 + dn[i1]
|
||||
alp1 := alp0 + (int32(rr[int(i1)*L+int(i1)]) << 14)
|
||||
alp1 += int32(rr[int(i0)*L+int(i1)]) << 15
|
||||
sq1 := int16((int32(ps1) * int32(ps1)) >> 15)
|
||||
alp16 := int16((alp1 + 0x8000) >> 16)
|
||||
s := (int32(alp)*int32(sq1))<<1 - (int32(sq)*int32(alp16))<<1
|
||||
if s > 0 {
|
||||
sq, ps, alp, ix = sq1, ps1, alp16, i1
|
||||
}
|
||||
}
|
||||
i1 := ix
|
||||
|
||||
ps0 = ps
|
||||
alp0 = int32(alp) << 14
|
||||
sq, alp, ps, ix = -1, 1, 0, ipos[2]
|
||||
for i2 := ipos[2]; i2 < L; i2 += cSTEP {
|
||||
ps1 := ps0 + dn[i2]
|
||||
alp1 := alp0 + (int32(rr[int(i2)*L+int(i2)]) << 12)
|
||||
alp1 += int32(rr[int(i1)*L+int(i2)]) << 13
|
||||
alp1 += int32(rr[int(i0)*L+int(i2)]) << 13
|
||||
sq1 := int16((int32(ps1) * int32(ps1)) >> 15)
|
||||
alp16 := int16((alp1 + 0x8000) >> 16)
|
||||
s := (int32(alp)*int32(sq1))<<1 - (int32(sq)*int32(alp16))<<1
|
||||
if s > 0 {
|
||||
sq, ps, alp, ix = sq1, ps1, alp16, i2
|
||||
}
|
||||
}
|
||||
i2 := ix
|
||||
|
||||
ps0 = ps
|
||||
alp0 = int32(alp) << 16
|
||||
sq, alp, ps, ix = -1, 1, 0, ipos[3]
|
||||
for i3 := ipos[3]; i3 < L; i3 += cSTEP {
|
||||
ps1 := ps0 + dn[i3]
|
||||
alp1 := alp0 + (int32(rr[int(i3)*L+int(i3)]) << 12)
|
||||
alp1 += int32(rr[int(i2)*L+int(i3)]) << 13
|
||||
alp1 += int32(rr[int(i1)*L+int(i3)]) << 13
|
||||
alp1 += int32(rr[int(i0)*L+int(i3)]) << 13
|
||||
sq1 := int16((int32(ps1) * int32(ps1)) >> 15)
|
||||
alp16 := int16((alp1 + 0x8000) >> 16)
|
||||
s := (int32(alp)*int32(sq1))<<1 - (int32(sq)*int32(alp16))<<1
|
||||
if s > 0 {
|
||||
sq, ps, alp, ix = sq1, ps1, alp16, i3
|
||||
}
|
||||
}
|
||||
|
||||
s := (int32(alpk)*int32(sq))<<1 - (int32(psk)*int32(alp))<<1
|
||||
if s > 0 {
|
||||
psk = sq
|
||||
alpk = alp
|
||||
codvec[0], codvec[1], codvec[2], codvec[3] = i0, i1, i2, ix
|
||||
}
|
||||
}
|
||||
pos := ipos[3]
|
||||
ipos[3] = ipos[2]
|
||||
ipos[2] = ipos[1]
|
||||
ipos[1] = ipos[0]
|
||||
ipos[0] = pos
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// build4Code assembles the 4-pulse innovation, filtered code, signs and the
|
||||
// Gray-coded 17-bit index. Mirrors build_code (c4_17pf.cpp).
|
||||
func build4Code(codvec, dnSign, cod, h, y []int16) (indx, sign int16) {
|
||||
const L = cL_CODE
|
||||
for i := 0; i < L; i++ {
|
||||
cod[i] = 0
|
||||
}
|
||||
|
||||
var sgn [4]int16
|
||||
rsign := int16(0)
|
||||
for k := 0; k < 4; k++ {
|
||||
i := codvec[k]
|
||||
j := dnSign[i]
|
||||
index := int16((int32(i) * 6554) >> 15)
|
||||
track := i - index*5
|
||||
index = gray[index]
|
||||
switch track {
|
||||
case 1:
|
||||
index <<= 3
|
||||
case 2:
|
||||
index <<= 6
|
||||
case 3:
|
||||
index <<= 10
|
||||
case 4:
|
||||
track = 3
|
||||
index = (index << 10) + 512
|
||||
}
|
||||
if j > 0 {
|
||||
cod[i] = 8191
|
||||
sgn[k] = 32767
|
||||
track = 1 << uint(track)
|
||||
rsign += track
|
||||
} else {
|
||||
cod[i] = -8192
|
||||
sgn[k] = -32768
|
||||
}
|
||||
indx += index
|
||||
}
|
||||
sign = rsign
|
||||
|
||||
c := [4]int{int(codvec[0]), int(codvec[1]), int(codvec[2]), int(codvec[3])}
|
||||
for i := 0; i < L; i++ {
|
||||
var s int32
|
||||
for k := 0; k < 4; k++ {
|
||||
if i-c[k] >= 0 {
|
||||
s = L_mac(s, h[i-c[k]], sgn[k])
|
||||
}
|
||||
}
|
||||
y[i] = round_(s)
|
||||
}
|
||||
return indx, sign
|
||||
}
|
||||
|
||||
// code4i40_17bits runs the full MR74/MR795 4-pulse search. Mirrors
|
||||
// code_4i40_17bits.
|
||||
func code4i40_17bits(x, h []int16, T0, pitchSharp int16, code, y []int16) (index, sign int16) {
|
||||
sharp := shl(pitchSharp, 1)
|
||||
if T0 < cL_CODE {
|
||||
for i := T0; i < cL_CODE; i++ {
|
||||
h[i] = add(h[i], mult(h[i-T0], sharp))
|
||||
}
|
||||
}
|
||||
|
||||
var dn, dn2, dnSign [cL_CODE]int16
|
||||
var rr [cL_CODE * cL_CODE]int16
|
||||
var codvec [4]int16
|
||||
|
||||
corHX(h, x, dn[:], 1)
|
||||
setSign(dn[:], dnSign[:], dn2[:], 4)
|
||||
corH(h, dnSign[:], rr[:])
|
||||
search4i40(dn[:], dn2[:], rr[:], codvec[:])
|
||||
index, sign = build4Code(codvec[:], dnSign[:], code, h, y)
|
||||
|
||||
if T0 < cL_CODE {
|
||||
for i := T0; i < cL_CODE; i++ {
|
||||
code[i] = add(code[i], mult(code[i-T0], sharp))
|
||||
}
|
||||
}
|
||||
return index, sign
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package amrnb
|
||||
|
||||
// 8-pulse algebraic codebook search (31 bits, MR102), ported from opencore-amrnb
|
||||
// c8_31pf.cpp. Drives search10and8i40 (8 pulses, step 4), then builds the
|
||||
// codeword and compresses the eight pulse positions / four track signs into the
|
||||
// 7-value transmitted index. The exact encoder counterpart of dec8i40_31bits
|
||||
// (decompressCode). Bit-exact with the reference.
|
||||
|
||||
// build8Code assembles the 8-pulse innovation cod and filtered code y, and the
|
||||
// linear track signs / pulse positions (with the same-track ordering/swap logic
|
||||
// that decompressCode inverts). Mirrors build_code (c8_31pf.cpp).
|
||||
func build8Code(codvec, sign, cod, h, y []int16) (signIndx [4]int16, posIndx [8]int16) {
|
||||
const L = cL_CODE
|
||||
for i := 0; i < L; i++ {
|
||||
cod[i] = 0
|
||||
}
|
||||
for t := 0; t < 4; t++ {
|
||||
posIndx[t] = -1
|
||||
signIndx[t] = -1
|
||||
}
|
||||
|
||||
var sgn [8]int16
|
||||
for k := 0; k < 8; k++ {
|
||||
i := codvec[k]
|
||||
j := sign[i]
|
||||
posIndex := i >> 2
|
||||
track := i & 3
|
||||
|
||||
var signIndex int16
|
||||
if j > 0 {
|
||||
cod[i] = cod[i] + 8191
|
||||
sgn[k] = 32767
|
||||
signIndex = 0
|
||||
} else {
|
||||
cod[i] = cod[i] - 8191
|
||||
sgn[k] = -32768
|
||||
signIndex = 1
|
||||
}
|
||||
|
||||
if posIndx[track] < 0 {
|
||||
posIndx[track] = posIndex
|
||||
signIndx[track] = signIndex
|
||||
} else if (signIndex^signIndx[track])&1 == 0 {
|
||||
if posIndx[track] <= posIndex {
|
||||
posIndx[track+4] = posIndex
|
||||
} else {
|
||||
posIndx[track+4] = posIndx[track]
|
||||
posIndx[track] = posIndex
|
||||
signIndx[track] = signIndex
|
||||
}
|
||||
} else {
|
||||
if posIndx[track] <= posIndex {
|
||||
posIndx[track+4] = posIndx[track]
|
||||
posIndx[track] = posIndex
|
||||
signIndx[track] = signIndex
|
||||
} else {
|
||||
posIndx[track+4] = posIndex
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < L; i++ {
|
||||
var s int32
|
||||
for k := 0; k < 8; k++ {
|
||||
ci := int(codvec[k])
|
||||
if i-ci >= 0 {
|
||||
s = L_mac(s, h[i-ci], sgn[k])
|
||||
}
|
||||
}
|
||||
y[i] = round_(s)
|
||||
}
|
||||
return signIndx, posIndx
|
||||
}
|
||||
|
||||
// compress10 packs three position indices into one 10-bit value. Mirrors
|
||||
// compress10 (the inverse of decompress10).
|
||||
func compress10(A, B, C int16) int16 {
|
||||
ia := A >> 1
|
||||
ib := (B >> 1) * 5
|
||||
ic := (C >> 1) * 25
|
||||
indx := (ib + ic + ia) << 3
|
||||
indx += ((B & 1) << 1) + ((C & 1) << 2) + (A & 1)
|
||||
return indx
|
||||
}
|
||||
|
||||
// compressCode packs the four track signs and eight pulse positions into the
|
||||
// seven transmitted index values. Mirrors compress_code.
|
||||
func compressCode(signIndx, posIndx, indx []int16) {
|
||||
for i := 0; i < 4; i++ {
|
||||
indx[i] = signIndx[i]
|
||||
}
|
||||
indx[4] = compress10(posIndx[0], posIndx[4], posIndx[1])
|
||||
indx[5] = compress10(posIndx[2], posIndx[6], posIndx[5])
|
||||
|
||||
ib := (posIndx[7] >> 1) & 1
|
||||
ia := posIndx[3] >> 1
|
||||
if ib == 1 {
|
||||
ia = 4 - ia
|
||||
}
|
||||
ib = (posIndx[7] >> 1) * 5
|
||||
ib += ia
|
||||
ib <<= 5
|
||||
ib += 12
|
||||
ic := int16((int32(ib) * 1311) >> 15)
|
||||
ic <<= 2
|
||||
ia = posIndx[3] & 1
|
||||
ib = (posIndx[7] & 1) << 1
|
||||
indx[6] = ib + ic + ia
|
||||
}
|
||||
|
||||
// code8i40_31bits runs the full MR102 8-pulse search, writing the innovation
|
||||
// cod, filtered code y, and the 7-value index. Mirrors code_8i40_31bits.
|
||||
func code8i40_31bits(x, cn, h, cod, y, indx []int16) {
|
||||
var dn, sign [cL_CODE]int16
|
||||
var rr [cL_CODE * cL_CODE]int16
|
||||
var ipos, codvec [8]int16
|
||||
var posMax [4]int16
|
||||
|
||||
corHX2(h, x, dn[:], 2, 4, 4)
|
||||
setSign12k2(dn[:], cn, sign[:], posMax[:], 4, ipos[:], 4)
|
||||
corH(h, sign[:], rr[:])
|
||||
search10and8i40(8, 4, 4, dn[:], rr[:], ipos[:], posMax[:], codvec[:])
|
||||
signIndx, posIndx := build8Code(codvec[:], sign[:], cod, h, y)
|
||||
compressCode(signIndx[:], posIndx[:], indx)
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package amrnb
|
||||
|
||||
// Algebraic-codebook search infrastructure, ported from opencore-amrnb
|
||||
// cor_h_x.cpp (cor_h_x) and set_sign.cpp (set_sign). corHX computes the
|
||||
// backward correlation dn[] between the search target and the weighted impulse
|
||||
// response (the gradient that drives pulse placement); setSign extracts the
|
||||
// per-position pulse signs and prunes each track to its strongest candidate
|
||||
// positions. These feed the per-mode pulse searches. Bit-exact with the
|
||||
// reference.
|
||||
|
||||
const (
|
||||
cNB_TRACK = 5 // number of pulse tracks
|
||||
cSTEP = 5 // codebook track step
|
||||
)
|
||||
|
||||
// corHX computes dn[i] = normalized 2·sum_j x[i+j]·h[j], the correlation between
|
||||
// the target x and the impulse response h, scaled so it fits 16 bits (sf is the
|
||||
// scaling factor: 2 for 12.2k, 1 otherwise). Mirrors cor_h_x.
|
||||
func corHX(h, x, dn []int16, sf int16) {
|
||||
// y32[i] = 2·sum_{j=0}^{L-1-i} x[i+j]·h[j]. Zero-padding x past L makes the
|
||||
// out-of-range taps contribute 0, so the whole set of positions is one L-tap
|
||||
// FIR over the padded input (firRaw). The per-term <<1 distributes over the
|
||||
// wrapping sum, so dst[i]<<1 is bit-identical to the per-term shift.
|
||||
var xpad [2 * cL_CODE]int16
|
||||
copy(xpad[:cL_CODE], x[:cL_CODE])
|
||||
var dst [cL_CODE]int32
|
||||
firRaw(dst[:], xpad[:], h[:cL_CODE])
|
||||
|
||||
var y32 [cL_CODE]int32
|
||||
for i := 0; i < cL_CODE; i++ {
|
||||
y32[i] = dst[i] << 1
|
||||
}
|
||||
|
||||
tot := int32(5)
|
||||
for k := 0; k < cNB_TRACK; k++ {
|
||||
var max int32
|
||||
for i := k; i < cL_CODE; i += cSTEP {
|
||||
s := y32[i]
|
||||
if s < 0 {
|
||||
s = -s
|
||||
}
|
||||
if s > max {
|
||||
max = s
|
||||
}
|
||||
}
|
||||
tot += max >> 1
|
||||
}
|
||||
|
||||
j := norm_l(tot) - sf
|
||||
for i := 0; i < cL_CODE; i++ {
|
||||
s := L_shl(y32[i], j)
|
||||
dn[i] = int16((s + 0x8000) >> 16)
|
||||
}
|
||||
}
|
||||
|
||||
// setSign records the sign of each dn[] entry (±32767), takes |dn|, and prunes
|
||||
// dn2[] to keep only the n strongest positions per track (the rest set to -1).
|
||||
// Mirrors set_sign.
|
||||
func setSign(dn, sign, dn2 []int16, n int16) {
|
||||
for i := 0; i < cL_CODE; i++ {
|
||||
val := dn[i]
|
||||
if val >= 0 {
|
||||
sign[i] = 32767
|
||||
} else {
|
||||
sign[i] = -32767
|
||||
val = negate(val)
|
||||
}
|
||||
dn[i] = val
|
||||
dn2[i] = val
|
||||
}
|
||||
|
||||
for i := 0; i < cNB_TRACK; i++ {
|
||||
for k := int16(0); k < 8-n; k++ {
|
||||
min := int16(0x7fff)
|
||||
pos := i
|
||||
for j := i; j < cL_CODE; j += cSTEP {
|
||||
if dn2[j] >= 0 && dn2[j] < min {
|
||||
min = dn2[j]
|
||||
pos = j
|
||||
}
|
||||
}
|
||||
dn2[pos] = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package amrnb
|
||||
|
||||
// Parameterized codebook-search correlation, ported from opencore-amrnb
|
||||
// cor_h_x2.cpp. corHX2 is the generalized form of corHX used by the multi-pulse
|
||||
// searches (MR102: 4 tracks, MR122: 5 tracks): dn[i] = normalized 2·Σ x[j]·h[j-i]
|
||||
// with a configurable track count and step. Bit-exact with the reference.
|
||||
|
||||
const cLOG2_OF_32 = 5
|
||||
|
||||
// corHX2 computes the normalized target↔impulse correlation dn[] over nbTrack
|
||||
// tracks with the given step, scaled by sf. Mirrors cor_h_x2.
|
||||
func corHX2(h, x, dn []int16, sf, nbTrack, step int16) {
|
||||
// y32[i] = 2·sum_{j=i}^{L-1} x[j]·h[j-i] = 2·sum_{j'=0}^{L-1-i} x[i+j']·h[j'].
|
||||
// Zero-padding x past L turns this into one L-tap FIR over the padded input
|
||||
// (firRaw); s<<1 == dst[i]<<1 holds mod 2^32 since <<1 distributes over the
|
||||
// wrapping sum.
|
||||
var xpad [2 * cL_CODE]int16
|
||||
copy(xpad[:cL_CODE], x[:cL_CODE])
|
||||
var dst [cL_CODE]int32
|
||||
firRaw(dst[:], xpad[:], h[:cL_CODE])
|
||||
|
||||
var y32 [cL_CODE]int32
|
||||
for i := 0; i < cL_CODE; i++ {
|
||||
y32[i] = dst[i] << 1
|
||||
}
|
||||
|
||||
tot := int32(cLOG2_OF_32)
|
||||
for k := int16(0); k < nbTrack; k++ {
|
||||
var max int32
|
||||
for i := k; i < cL_CODE; i += step {
|
||||
if a := L_abs(y32[i]); a > max {
|
||||
max = a
|
||||
}
|
||||
}
|
||||
tot += max >> 1
|
||||
}
|
||||
|
||||
j := norm_l(tot) - sf
|
||||
for i := 0; i < cL_CODE; i++ {
|
||||
dn[i] = round_(L_shl(y32[i], j))
|
||||
}
|
||||
}
|
||||
|
||||
// setSign12k2 combines the residual cn and the correlation dn to determine each
|
||||
// position's pulse sign, the per-track maximum positions (posMax), and a cyclic
|
||||
// pulse-track ordering (ipos, length 2*nbTrack) starting from the strongest
|
||||
// track — the prep for the multi-pulse search_10and8i40. dn is updated in place
|
||||
// (negated where the combined sign is negative). Mirrors set_sign12k2.
|
||||
func setSign12k2(dn, cn, sign, posMax []int16, nbTrack int16, ipos []int16, step int16) {
|
||||
const L = cL_CODE
|
||||
var en [cL_CODE]int16
|
||||
|
||||
s := int32(256)
|
||||
t := int32(256)
|
||||
for i := 0; i < L; i++ {
|
||||
s = L_mac(s, cn[i], cn[i])
|
||||
t += (int32(dn[i]) * int32(dn[i])) << 1
|
||||
}
|
||||
s = invSqrt(s)
|
||||
kCn := int16(L_shl(s, 5) >> 16)
|
||||
t = invSqrt(t)
|
||||
kDn := int16(t >> 11)
|
||||
|
||||
for i := L - 1; i >= 0; i-- {
|
||||
lTemp := (int32(kCn) * int32(cn[i])) << 1
|
||||
val := dn[i]
|
||||
ss := L_mac(lTemp, kDn, val)
|
||||
cor := round_(L_shl(ss, 10))
|
||||
if cor >= 0 {
|
||||
sign[i] = 32767
|
||||
} else {
|
||||
sign[i] = -32767
|
||||
cor = negate(cor)
|
||||
dn[i] = negate(val)
|
||||
}
|
||||
en[i] = cor
|
||||
}
|
||||
|
||||
maxOfAll := int16(-1)
|
||||
var pos int16
|
||||
for i := int16(0); i < nbTrack; i++ {
|
||||
max := int16(-1)
|
||||
for j := i; j < L; j += step {
|
||||
if en[j] > max {
|
||||
max = en[j]
|
||||
pos = j
|
||||
}
|
||||
}
|
||||
posMax[i] = pos
|
||||
if max > maxOfAll {
|
||||
maxOfAll = max
|
||||
ipos[0] = i
|
||||
}
|
||||
}
|
||||
|
||||
pos = ipos[0]
|
||||
ipos[nbTrack] = pos
|
||||
for i := int16(1); i < nbTrack; i++ {
|
||||
pos++
|
||||
if pos >= nbTrack {
|
||||
pos = 0
|
||||
}
|
||||
ipos[i] = pos
|
||||
ipos[i+nbTrack] = pos
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package amrnb
|
||||
|
||||
// Closed-loop long-term-prediction (adaptive codebook) step, ported from
|
||||
// opencore-amrnb cl_ltp.cpp. clLtp runs the fractional pitch search (pitchFr),
|
||||
// builds the adaptive codebook (predLt), filters it (convolve), computes the
|
||||
// pitch gain (gPitch) with mode-specific clamping (and MR122 quantization), then
|
||||
// forms the codebook-search target xn2 = xn - gain·y1 and updates res2. The
|
||||
// tone-stabilization gain clip (gpc_flag) is not applied (active-speech path).
|
||||
// Bit-exact with the reference for that path.
|
||||
|
||||
const cGP_CLIP = 15565 // 0.95 Q14 pitch-gain clip
|
||||
|
||||
type clLtpResult struct {
|
||||
T0, T0frac int16
|
||||
gainPit int16
|
||||
gpLimit int16
|
||||
gCoeff [5]int16
|
||||
pitchIndex int16
|
||||
gainPitIndex int16 // MR122 only
|
||||
hasGainPitIndex bool
|
||||
}
|
||||
|
||||
// clLtp performs the adaptive-codebook analysis for one subframe. exc[excOff] is
|
||||
// the current subframe; predLt writes it in place. xn2 (codebook target) and
|
||||
// res2 (residual) are written. Mirrors cl_ltp.
|
||||
func (st *pitchFrState) clLtp(mode, frameOffset int, Top, h1, exc []int16, excOff int, res2, xn, xn2, yl []int16) clLtpResult {
|
||||
var r clLtpResult
|
||||
resu3 := int16(0)
|
||||
r.T0, r.T0frac, resu3, r.pitchIndex = st.pitchFr(mode, Top, exc, excOff, xn, h1, cL_SUBFR, frameOffset)
|
||||
|
||||
predLt(exc, excOff, r.T0, r.T0frac, cL_SUBFR, resu3)
|
||||
convolve(exc[excOff:], h1, yl, cL_SUBFR)
|
||||
|
||||
r.gainPit = gPitch(mode, xn, yl, r.gCoeff[:], cL_SUBFR)
|
||||
r.gpLimit = maxInt16 // tone-stabilization clip disabled
|
||||
|
||||
if mode == dMR475 || mode == dMR515 {
|
||||
if r.gainPit > 13926 {
|
||||
r.gainPit = 13926
|
||||
}
|
||||
} else if mode == dMR122 {
|
||||
var cand, cind [3]int16
|
||||
r.gainPitIndex = qGainPitch(dMR122, r.gpLimit, &r.gainPit, cand[:], cind[:])
|
||||
r.hasGainPitIndex = true
|
||||
}
|
||||
|
||||
g := r.gainPit
|
||||
for i := 0; i < cL_SUBFR; i++ {
|
||||
xn2[i] = xn[i] - int16((int32(yl[i])*int32(g))>>14)
|
||||
res2[i] -= int16((int32(exc[excOff+i]) * int32(g)) >> 14)
|
||||
}
|
||||
return r
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
package amrnb
|
||||
|
||||
// Closed-loop fractional pitch search, ported from opencore-amrnb pitch_fr.cpp
|
||||
// (Pitch_fr, Norm_Corr, searchFrac, getRange) and inter_36.cpp (Interpol_3or6).
|
||||
// pitchFr refines the open-loop lag: it builds the normalized correlation of the
|
||||
// target with the filtered adaptive excitation over an integer search range,
|
||||
// picks the best integer lag, then interpolates to a fractional lag, and encodes
|
||||
// the result with encLag3/encLag6. Bit-exact with the reference.
|
||||
|
||||
const cL_INTER_SRCH = 4 // closed-loop pitch search interpolation half-length
|
||||
|
||||
// mode-dependent search parameters (pitch_fr.cpp mode_dep_parm), indexed by the
|
||||
// internal speech mode 0..7.
|
||||
var modeDepParm = [8]struct {
|
||||
maxFracLag, flag3, firstFrac, lastFrac int16
|
||||
deltaIntLow, deltaIntRange, deltaFrcLow int16
|
||||
deltaFrcRange, pitMin int16
|
||||
}{
|
||||
{84, 1, -2, 2, 5, 10, 5, 9, cPIT_MIN}, // MR475
|
||||
{84, 1, -2, 2, 5, 10, 5, 9, cPIT_MIN}, // MR515
|
||||
{84, 1, -2, 2, 3, 6, 5, 9, cPIT_MIN}, // MR59
|
||||
{84, 1, -2, 2, 3, 6, 5, 9, cPIT_MIN}, // MR67
|
||||
{84, 1, -2, 2, 3, 6, 5, 9, cPIT_MIN}, // MR74
|
||||
{84, 1, -2, 2, 3, 6, 10, 19, cPIT_MIN}, // MR795
|
||||
{84, 1, -2, 2, 3, 6, 5, 9, cPIT_MIN}, // MR102
|
||||
{94, 0, -3, 3, 3, 6, 5, 9, cPIT_MIN_MR122}, // MR122
|
||||
}
|
||||
|
||||
// pitchFrState carries the previous subframe's integer lag across subframes.
|
||||
type pitchFrState struct {
|
||||
T0prev int16
|
||||
}
|
||||
|
||||
func (st *pitchFrState) reset() { st.T0prev = 0 }
|
||||
|
||||
// getRange clamps a search range [t0min, t0max] of width deltaRange around T0.
|
||||
// Mirrors getRange.
|
||||
func getRange(T0, deltaLow, deltaRange, pitmin, pitmax int16) (t0min, t0max int16) {
|
||||
temp := T0 - deltaLow
|
||||
if temp < pitmin {
|
||||
temp = pitmin
|
||||
}
|
||||
t0min = temp
|
||||
temp += deltaRange
|
||||
if temp > pitmax {
|
||||
temp = pitmax
|
||||
t0min = pitmax - deltaRange
|
||||
}
|
||||
t0max = temp
|
||||
return t0min, t0max
|
||||
}
|
||||
|
||||
// normCorr computes the normalized correlation corr[t-tMin] of the target xn
|
||||
// with the adaptive excitation at each integer lag t in [tMin, tMax], filtered
|
||||
// by the impulse response h. exc[excOff] is the current subframe start. Mirrors
|
||||
// Norm_Corr.
|
||||
func normCorr(exc []int16, excOff int, xn, h []int16, Lsubfr int, tMin, tMax int16, corr []int16) {
|
||||
var excf, scaledExcf [cL_SUBFR]int16
|
||||
|
||||
k := -int(tMin)
|
||||
convolve(exc[excOff+k:], h, excf[:], Lsubfr)
|
||||
|
||||
var s int32
|
||||
for j := 0; j < Lsubfr; j++ {
|
||||
t := excf[j]
|
||||
scaledExcf[j] = t >> 2
|
||||
s += int32(t) * int32(t)
|
||||
}
|
||||
|
||||
var sExcf []int16
|
||||
var hFac, scaling int16
|
||||
if s <= (67108864 >> 1) {
|
||||
sExcf = excf[:]
|
||||
hFac = 12
|
||||
scaling = 0
|
||||
} else {
|
||||
sExcf = scaledExcf[:]
|
||||
hFac = 14
|
||||
scaling = 2
|
||||
}
|
||||
|
||||
xnf := xn[:Lsubfr] // hoist bounds out of the inner correlation loop
|
||||
sef := sExcf[:Lsubfr] // (both length Lsubfr)
|
||||
hf := h[:Lsubfr]
|
||||
for i := tMin; i <= tMax; i++ {
|
||||
sc := firDot(xnf, sef)
|
||||
s2 := firDot(sef, sef)
|
||||
s2 <<= 1
|
||||
s2 = invSqrt(s2)
|
||||
normH := int16(s2 >> 16)
|
||||
normL := int16((s2 >> 1) - (int32(normH) << 15))
|
||||
corrH := int16(sc >> 15)
|
||||
corrL := int16(sc - (int32(corrH) << 15))
|
||||
corr[int(i)-int(tMin)] = int16(mpy_32(corrH, corrL, normH, normL))
|
||||
|
||||
if i != tMax {
|
||||
k--
|
||||
temp := exc[excOff+k]
|
||||
for j := Lsubfr - 1; j >= 1; j-- {
|
||||
sef[j] = int16((int32(temp)*int32(hf[j]))>>uint(hFac)) + sef[j-1]
|
||||
}
|
||||
sef[0] = temp >> scaling
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// interpol3or6 interpolates the correlation around corr[off] at fractional
|
||||
// position frac (1/3 if flag3 else 1/6). Mirrors Interpol_3or6.
|
||||
func interpol3or6(corr []int16, off int, frac, flag3 int16) int16 {
|
||||
if flag3 != 0 {
|
||||
frac <<= 1
|
||||
}
|
||||
if frac < 0 {
|
||||
frac += cUP_SAMP_MAX
|
||||
off--
|
||||
}
|
||||
f := int(frac)
|
||||
s := int32(0x4000)
|
||||
k := 0
|
||||
x1 := off
|
||||
x2 := off + 1
|
||||
for i := cL_INTER_SRCH >> 1; i != 0; i-- {
|
||||
s += int32(corr[x1]) * int32(inter6Pitch[f+k])
|
||||
x1--
|
||||
s += int32(corr[x2]) * int32(inter6Pitch[(cUP_SAMP_MAX-f)+k])
|
||||
x2++
|
||||
k += cUP_SAMP_MAX
|
||||
s += int32(corr[x1]) * int32(inter6Pitch[f+k])
|
||||
x1--
|
||||
s += int32(corr[x2]) * int32(inter6Pitch[(cUP_SAMP_MAX-f)+k])
|
||||
x2++
|
||||
k <<= 1
|
||||
}
|
||||
return int16(s >> 15)
|
||||
}
|
||||
|
||||
// searchFrac refines the fractional pitch around the integer lag by maximizing
|
||||
// the interpolated correlation, then normalizes the (lag, frac) pair. Mirrors
|
||||
// searchFrac.
|
||||
func searchFrac(lag, frac *int16, lastFrac int16, corr []int16, tMin int, flag3 int16) {
|
||||
off := int(*lag) - tMin
|
||||
max := interpol3or6(corr, off, *frac, flag3)
|
||||
for i := *frac + 1; i <= lastFrac; i++ {
|
||||
ci := interpol3or6(corr, off, i, flag3)
|
||||
if ci > max {
|
||||
max = ci
|
||||
*frac = i
|
||||
}
|
||||
}
|
||||
if flag3 == 0 {
|
||||
if *frac == -3 {
|
||||
*frac = 3
|
||||
*lag--
|
||||
}
|
||||
} else {
|
||||
if *frac == -2 {
|
||||
*frac = 1
|
||||
*lag--
|
||||
}
|
||||
if *frac == 2 {
|
||||
*frac = -1
|
||||
*lag++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pitchFr performs the closed-loop fractional pitch search for one subframe and
|
||||
// returns the integer lag T0, fractional part frac, the resolution flag resu3
|
||||
// (1=1/3, 0=1/6), and the encoded analysis index. Mirrors Pitch_fr.
|
||||
func (st *pitchFrState) pitchFr(mode int, Top []int16, exc []int16, excOff int, xn, h []int16, Lsubfr, iSubfr int) (T0, frac, resu3, anaIndex int16) {
|
||||
p := modeDepParm[mode]
|
||||
maxFracLag := p.maxFracLag
|
||||
flag3 := p.flag3
|
||||
frac = p.firstFrac
|
||||
lastFrac := p.lastFrac
|
||||
|
||||
deltaSearch := int16(1)
|
||||
var t0min, t0max int16
|
||||
if iSubfr == 0 || iSubfr == cL_FRAME_BY2 {
|
||||
if (mode != dMR475 && mode != dMR515) || iSubfr != cL_FRAME_BY2 {
|
||||
deltaSearch = 0
|
||||
frameOffset := int16(1)
|
||||
if iSubfr == 0 {
|
||||
frameOffset = 0
|
||||
}
|
||||
t0min, t0max = getRange(Top[frameOffset], p.deltaIntLow, p.deltaIntRange, p.pitMin, cPIT_MAX)
|
||||
} else {
|
||||
t0min, t0max = getRange(st.T0prev, p.deltaFrcLow, p.deltaFrcRange, p.pitMin, cPIT_MAX)
|
||||
}
|
||||
} else {
|
||||
t0min, t0max = getRange(st.T0prev, p.deltaFrcLow, p.deltaFrcRange, p.pitMin, cPIT_MAX)
|
||||
}
|
||||
|
||||
tMin := int16(int(t0min) - cL_INTER_SRCH)
|
||||
tMax := int16(int(t0max) + cL_INTER_SRCH)
|
||||
corr := make([]int16, int(tMax)-int(tMin)+1)
|
||||
normCorr(exc, excOff, xn, h, Lsubfr, tMin, tMax, corr)
|
||||
|
||||
max := corr[int(t0min)-int(tMin)]
|
||||
lag := t0min
|
||||
for i := t0min + 1; i <= t0max; i++ {
|
||||
if corr[int(i)-int(tMin)] >= max {
|
||||
max = corr[int(i)-int(tMin)]
|
||||
lag = i
|
||||
}
|
||||
}
|
||||
|
||||
if deltaSearch == 0 && lag > maxFracLag {
|
||||
frac = 0
|
||||
} else if deltaSearch != 0 && (mode == dMR475 || mode == dMR515 || mode == dMR59 || mode == dMR67) {
|
||||
tmpLag := st.T0prev
|
||||
if tmpLag-t0min > 5 {
|
||||
tmpLag = t0min + 5
|
||||
}
|
||||
if t0max-tmpLag > 4 {
|
||||
tmpLag = t0max - 4
|
||||
}
|
||||
switch {
|
||||
case lag == tmpLag || lag == tmpLag-1:
|
||||
searchFrac(&lag, &frac, lastFrac, corr, int(tMin), flag3)
|
||||
case lag == tmpLag-2:
|
||||
frac = 0
|
||||
searchFrac(&lag, &frac, lastFrac, corr, int(tMin), flag3)
|
||||
case lag == tmpLag+1:
|
||||
lastFrac = 0
|
||||
searchFrac(&lag, &frac, lastFrac, corr, int(tMin), flag3)
|
||||
default:
|
||||
frac = 0
|
||||
}
|
||||
} else {
|
||||
searchFrac(&lag, &frac, lastFrac, corr, int(tMin), flag3)
|
||||
}
|
||||
|
||||
if flag3 != 0 {
|
||||
flag4 := int16(0)
|
||||
if mode == dMR475 || mode == dMR515 || mode == dMR59 || mode == dMR67 {
|
||||
flag4 = 1
|
||||
}
|
||||
anaIndex = encLag3(lag, frac, st.T0prev, t0min, t0max, deltaSearch, flag4)
|
||||
} else {
|
||||
anaIndex = encLag6(lag, frac, t0min, deltaSearch)
|
||||
}
|
||||
|
||||
st.T0prev = lag
|
||||
resu3 = flag3
|
||||
return lag, frac, resu3, anaIndex
|
||||
}
|
||||
@@ -0,0 +1,356 @@
|
||||
package amrnb
|
||||
|
||||
// Main encoder driver, ported from opencore-amrnb cod_amr.cpp (cod_amr) and the
|
||||
// per-frame wrapper sp_enc.cpp (Speech_Encode_Frame). It ties together the LP
|
||||
// analysis (lpc), LSP quantization (lsp), perceptual weighting + open-loop pitch
|
||||
// (pre_big/ol_ltp), and the four-subframe analysis-by-synthesis loop
|
||||
// (subframePreProc -> clLtp -> cbsearch -> gainQuant -> subframePostProc),
|
||||
// producing the parameter array consumed by prm2bits/packFrame.
|
||||
//
|
||||
// Scope: the active-speech path for all eight modes — MR515/MR59/MR67/MR74/MR102
|
||||
// via Qua_gain, MR122 via q_gain_code, MR475 via the joint two-subframe VQ
|
||||
// (mr475Loop), and MR795 via the gain-adapted quantizer. MR102 uses the weighted
|
||||
// open-loop pitch (pitchOlWgh). DTX/VAD is always-active. All eight modes are
|
||||
// bit-exact with the opencore-amrnb reference encoder.
|
||||
|
||||
// buffer offsets within oldSpeech (length cL_TOTAL).
|
||||
const (
|
||||
cSpeechOff = cL_TOTAL - cL_FRAME - cL_NEXT // 120: present frame start
|
||||
cPWindowOff = cL_TOTAL - cL_WINDOW // 80: LPC analysis window
|
||||
cPWin122Off = cPWindowOff - cL_NEXT // 40: EFR (MR122) window, no lookahead
|
||||
cNewSpchOff = cL_TOTAL - cL_FRAME // 160: new speech
|
||||
)
|
||||
|
||||
// coderState holds the persistent encoder analysis state across frames,
|
||||
// mirroring cod_amrState plus the Pre_Process state.
|
||||
type coderState struct {
|
||||
oldSpeech [cL_TOTAL]int16 // [history | present | lookahead]
|
||||
oldWsp [cPIT_MAX + cL_FRAME]int16 // weighted speech with pitch history
|
||||
oldExc [cExcOff + cL_FRAME]int16 // excitation with pitch+interp history
|
||||
|
||||
pre preProcessState
|
||||
lspS lspEncState
|
||||
pred gcPredState
|
||||
predUnq gcPredState // "unquantized" gain predictor (MR475 only)
|
||||
adapt gainAdaptState // gain adaptor (MR795 only)
|
||||
pit pitchFrState
|
||||
pitWght pitchOLWghtState // weighted open-loop pitch (MR102 only)
|
||||
lev levinsonState
|
||||
|
||||
oldLags [5]int16 // closed-loop lag history (MR102 weighted OLP)
|
||||
olGainFlg [2]int16 // per-half-frame open-loop gain flag (MR102)
|
||||
prmBuf [64]int16 // reused parameter array (max params = 57, MR122)
|
||||
|
||||
memSyn [cM]int16
|
||||
memW0 [cM]int16
|
||||
memErr [cM]int16
|
||||
memW [cM]int16 // weighting-filter memory for pre_big
|
||||
sharp int16
|
||||
|
||||
// MR475 joint-pair quantizer state carried from the even to the odd subframe
|
||||
sf0ExpGcode0, sf0FracGcode0 int16
|
||||
sf0FracCoeff, sf0ExpCoeff [5]int16
|
||||
sf0ExpTargetEn, sf0FracTargetEn int16
|
||||
}
|
||||
|
||||
func (st *coderState) reset() {
|
||||
*st = coderState{}
|
||||
st.lspS.reset()
|
||||
st.pred.reset()
|
||||
st.pit.reset()
|
||||
st.pitWght.reset()
|
||||
for i := range st.oldLags {
|
||||
st.oldLags[i] = 40
|
||||
}
|
||||
st.sharp = 0 // SHARPMIN
|
||||
}
|
||||
|
||||
// lpcAnalysis runs the windowed autocorrelation + Levinson chain, filling the
|
||||
// per-window LP filters in az: az[3*MP1] (A_new) always, and az[MP1] (A_mid) for
|
||||
// MR122. Mirrors lpc.
|
||||
func (st *coderState) lpcAnalysis(mode int, az []int16) {
|
||||
var rh, rl [cMP1]int16
|
||||
var rc [4]int16
|
||||
if mode == dMR122 {
|
||||
autocorr(st.oldSpeech[cPWin122Off:], cM, rh[:], rl[:], window_160_80)
|
||||
lagWindow(cM, rh[:], rl[:])
|
||||
st.lev.levinson(rh[:], rl[:], az[cMP1:], rc[:])
|
||||
|
||||
autocorr(st.oldSpeech[cPWin122Off:], cM, rh[:], rl[:], window_232_8)
|
||||
lagWindow(cM, rh[:], rl[:])
|
||||
st.lev.levinson(rh[:], rl[:], az[3*cMP1:], rc[:])
|
||||
return
|
||||
}
|
||||
autocorr(st.oldSpeech[cPWindowOff:], cM, rh[:], rl[:], window_200_40)
|
||||
lagWindow(cM, rh[:], rl[:])
|
||||
st.lev.levinson(rh[:], rl[:], az[3*cMP1:], rc[:])
|
||||
}
|
||||
|
||||
// preBig computes the perceptually weighted speech wsp for the two subframes of
|
||||
// one half-frame (frameOffset 0 or L_FRAME_BY2), updating the weighting-filter
|
||||
// memory memW. Mirrors pre_big.
|
||||
func (st *coderState) preBig(mode, frameOffset int, az []int16) {
|
||||
g1 := gamma1[:]
|
||||
if mode > dMR795 { // MR102, MR122
|
||||
g1 = gamma1_12k2[:]
|
||||
}
|
||||
aOffset := 0
|
||||
if frameOffset > 0 {
|
||||
aOffset = cMP1 * 2
|
||||
}
|
||||
fo := frameOffset
|
||||
for i := 0; i < 2; i++ {
|
||||
var ap1, ap2 [cMP1]int16
|
||||
weightAi(az[aOffset:], g1, ap1[:])
|
||||
weightAi(az[aOffset:], gamma2[:], ap2[:])
|
||||
residu(ap1[:], st.oldSpeech[:], cSpeechOff+fo, cL_SUBFR, st.oldWsp[cPIT_MAX+fo:])
|
||||
w := st.oldWsp[cPIT_MAX+fo : cPIT_MAX+fo+cL_SUBFR]
|
||||
synFilt(ap2[:], w, w, cL_SUBFR, st.memW[:], true)
|
||||
aOffset += cMP1
|
||||
fo += cL_SUBFR
|
||||
}
|
||||
}
|
||||
|
||||
// gainQuant quantizes the subframe gains for the non-MR475 modes, writing the
|
||||
// quantization index/indices into prm, returning the quantized gains and the
|
||||
// number of indices written, and advancing the predictor. res/exc are the LP
|
||||
// residual and adaptive-codebook excitation (used only by MR795). Mirrors the
|
||||
// non-MR475 branch of gainQuant.
|
||||
func (st *coderState) gainQuant(mode int, r clLtpResult, xn, xn2, y1, y2, code, res, exc, prm []int16) (gainPit, gainCode int16, nIdx int) {
|
||||
gp := st.pred.gcPred(mode, code)
|
||||
var qe122, qe int16
|
||||
switch {
|
||||
case mode == dMR122:
|
||||
gainPit = r.gainPit // already quantized in cl_ltp
|
||||
gainCode = gCode(xn2, y2)
|
||||
var idx int16
|
||||
idx, qe122, qe = qGainCode(mode, gp.expGcode0, gp.fracGcode0, &gainCode)
|
||||
prm[0] = idx
|
||||
nIdx = 1
|
||||
case mode == dMR795:
|
||||
fc, ec, cgFrac, cgExp := calcFiltEnergies(mode, xn, xn2, y1, y2, r.gCoeff[:])
|
||||
gainPit = r.gainPit
|
||||
var gpIdx, gcIdx int16
|
||||
gainCode, qe122, qe, gpIdx, gcIdx = st.mr795GainQuant(res, exc, code, fc[:], ec[:],
|
||||
gp.expEn, gp.fracEn, gp.expGcode0, gp.fracGcode0, cgFrac, cgExp, r.gpLimit, &gainPit)
|
||||
prm[0], prm[1] = gpIdx, gcIdx
|
||||
nIdx = 2
|
||||
default:
|
||||
fc, ec, _, _ := calcFiltEnergies(mode, xn, xn2, y1, y2, r.gCoeff[:])
|
||||
var idx int16
|
||||
idx, gainPit, gainCode, qe122, qe = quaGain(mode, gp.expGcode0, gp.fracGcode0, fc[:], ec[:], r.gpLimit)
|
||||
prm[0] = idx
|
||||
nIdx = 1
|
||||
}
|
||||
st.pred.update(qe122, qe)
|
||||
return
|
||||
}
|
||||
|
||||
// codAmr encodes one pre-processed 160-sample frame, returning the parameter
|
||||
// array (LSF indices followed by the per-subframe pitch/codebook/gain indices,
|
||||
// in prm2bits order). Mirrors cod_amr for the supported modes.
|
||||
func (st *coderState) codAmr(mode int, newSpeech []int16) ([]int16, error) {
|
||||
copy(st.oldSpeech[cNewSpchOff:], newSpeech[:cL_FRAME])
|
||||
|
||||
az := make([]int16, cNB_SUBFR*cMP1)
|
||||
azQ := make([]int16, cNB_SUBFR*cMP1)
|
||||
st.lpcAnalysis(mode, az)
|
||||
|
||||
prm := st.prmBuf[:len(bitno[Mode(mode)])] // reused; caller serializes it before the next frame
|
||||
ap := st.lspS.lsp(mode, az, azQ, prm)
|
||||
|
||||
st.preBig(mode, 0, az)
|
||||
st.preBig(mode, cL_FRAME_BY2, az)
|
||||
var Top [2]int16
|
||||
if mode == dMR475 || mode == dMR515 {
|
||||
Top[0] = pitchOl(mode, st.oldWsp[:], cPIT_MAX, cPIT_MIN, cPIT_MAX, cL_FRAME)
|
||||
Top[1] = Top[0]
|
||||
} else {
|
||||
Top[0] = st.olPitch(mode, 0)
|
||||
Top[1] = st.olPitch(mode, cL_FRAME_BY2)
|
||||
}
|
||||
|
||||
synth := make([]int16, cL_FRAME)
|
||||
if mode == dMR475 {
|
||||
st.mr475Loop(az, azQ, Top[:], prm, ap, synth)
|
||||
copy(st.oldExc[:cExcOff], st.oldExc[cL_FRAME:cL_FRAME+cExcOff])
|
||||
copy(st.oldWsp[:cPIT_MAX], st.oldWsp[cL_FRAME:cL_FRAME+cPIT_MAX])
|
||||
copy(st.oldSpeech[:cL_TOTAL-cL_FRAME], st.oldSpeech[cL_FRAME:cL_TOTAL])
|
||||
return prm, nil
|
||||
}
|
||||
for subfrNr := 0; subfrNr < cNB_SUBFR; subfrNr++ {
|
||||
iSubfr := subfrNr * cL_SUBFR
|
||||
aSub := az[subfrNr*cMP1:]
|
||||
aqSub := azQ[subfrNr*cMP1:]
|
||||
excBase := cExcOff + iSubfr
|
||||
|
||||
xn := make([]int16, cL_SUBFR)
|
||||
res := make([]int16, cL_SUBFR)
|
||||
errSig := make([]int16, cL_SUBFR)
|
||||
h1 := make([]int16, cL_SUBFR)
|
||||
subframePreProc(mode, aSub, aqSub, st.oldSpeech[:], cSpeechOff+iSubfr,
|
||||
st.memErr[:], st.memW0[:], st.oldExc[excBase:], h1, xn, res, errSig)
|
||||
|
||||
res2 := make([]int16, cL_SUBFR)
|
||||
copy(res2, res)
|
||||
|
||||
xn2 := make([]int16, cL_SUBFR)
|
||||
y1 := make([]int16, cL_SUBFR)
|
||||
r := st.pit.clLtp(mode, iSubfr, Top[:], h1, st.oldExc[:], excBase, res2, xn, xn2, y1)
|
||||
// MR102: feed the first/last closed-loop lag back into the OLP history
|
||||
if subfrNr == 0 && st.olGainFlg[0] > 0 {
|
||||
st.oldLags[1] = r.T0
|
||||
} else if subfrNr == 3 && st.olGainFlg[1] > 0 {
|
||||
st.oldLags[0] = r.T0
|
||||
}
|
||||
prm[ap] = r.pitchIndex
|
||||
ap++
|
||||
if r.hasGainPitIndex {
|
||||
prm[ap] = r.gainPitIndex
|
||||
ap++
|
||||
}
|
||||
|
||||
code := make([]int16, cL_SUBFR)
|
||||
y2 := make([]int16, cL_SUBFR)
|
||||
ncb := cbsearch(xn2, h1, r.T0, st.sharp, r.gainPit, res2, code, y2, mode, subfrNr, prm[ap:])
|
||||
ap += ncb
|
||||
|
||||
gainPit, gainCode, ng := st.gainQuant(mode, r, xn, xn2, y1, y2, code, res, st.oldExc[excBase:], prm[ap:])
|
||||
ap += ng
|
||||
|
||||
subframePostProc(st.oldSpeech[:], cSpeechOff, mode, iSubfr, gainPit, gainCode,
|
||||
aqSub, synth, xn, code, y1, y2, st.memSyn[:], st.memErr[:], st.memW0[:],
|
||||
st.oldExc[:], cExcOff, &st.sharp)
|
||||
}
|
||||
|
||||
// slide the analysis buffers left by one frame
|
||||
copy(st.oldExc[:cExcOff], st.oldExc[cL_FRAME:cL_FRAME+cExcOff])
|
||||
copy(st.oldWsp[:cPIT_MAX], st.oldWsp[cL_FRAME:cL_FRAME+cPIT_MAX])
|
||||
copy(st.oldSpeech[:cL_TOTAL-cL_FRAME], st.oldSpeech[cL_FRAME:cL_TOTAL])
|
||||
|
||||
return prm, nil
|
||||
}
|
||||
|
||||
// mr475Loop runs the four-subframe analysis-by-synthesis loop for MR475, whose
|
||||
// gains are quantized two subframes at a time. Each even subframe is processed
|
||||
// tentatively (storing its energy terms and an unquantized synthesis), and at
|
||||
// the following odd subframe the joint VQ chooses one index for the pair; both
|
||||
// subframes' final syntheses are then redone with the reconstructed gains.
|
||||
// Mirrors the MR475 branch of cod_amr.
|
||||
func (st *coderState) mr475Loop(az, azQ, Top, prm []int16, ap int, synth []int16) {
|
||||
const mode = dMR475
|
||||
var memSynSave, memW0Save, memErrSave [cM]int16
|
||||
var h1Sf0, xnSf0, y2Sf0, codeSf0 [cL_SUBFR]int16
|
||||
var sharpSave, gainPitSf0, gainCodeSf0, T0Sf0, T0fracSf0 int16
|
||||
var iSubfrSf0, gainIdxPos int
|
||||
|
||||
for subfrNr := 0; subfrNr < cNB_SUBFR; subfrNr++ {
|
||||
iSubfr := subfrNr * cL_SUBFR
|
||||
evenSubfr := (subfrNr & 1) == 0
|
||||
aSub := az[subfrNr*cMP1:]
|
||||
aqSub := azQ[subfrNr*cMP1:]
|
||||
excBase := cExcOff + iSubfr
|
||||
|
||||
if evenSubfr {
|
||||
memSynSave = st.memSyn
|
||||
memW0Save = st.memW0
|
||||
memErrSave = st.memErr
|
||||
sharpSave = st.sharp
|
||||
}
|
||||
|
||||
// Both subframes of the pair build their target from memW0Save so the
|
||||
// even subframe's tentative synthesis carries into the odd one.
|
||||
xn := make([]int16, cL_SUBFR)
|
||||
res := make([]int16, cL_SUBFR)
|
||||
errSig := make([]int16, cL_SUBFR)
|
||||
h1 := make([]int16, cL_SUBFR)
|
||||
subframePreProc(mode, aSub, aqSub, st.oldSpeech[:], cSpeechOff+iSubfr,
|
||||
st.memErr[:], memW0Save[:], st.oldExc[excBase:], h1, xn, res, errSig)
|
||||
if evenSubfr {
|
||||
copy(h1Sf0[:], h1)
|
||||
}
|
||||
res2 := make([]int16, cL_SUBFR)
|
||||
copy(res2, res)
|
||||
|
||||
xn2 := make([]int16, cL_SUBFR)
|
||||
y1 := make([]int16, cL_SUBFR)
|
||||
r := st.pit.clLtp(mode, iSubfr, Top, h1, st.oldExc[:], excBase, res2, xn, xn2, y1)
|
||||
prm[ap] = r.pitchIndex
|
||||
ap++
|
||||
|
||||
code := make([]int16, cL_SUBFR)
|
||||
y2 := make([]int16, cL_SUBFR)
|
||||
ap += cbsearch(xn2, h1, r.T0, st.sharp, r.gainPit, res2, code, y2, mode, subfrNr, prm[ap:])
|
||||
|
||||
if evenSubfr {
|
||||
gainIdxPos = ap // reserve the joint gain index slot
|
||||
ap++
|
||||
|
||||
st.predUnq = st.pred // gc_pred_copy
|
||||
gpu := st.predUnq.gcPred(mode, code)
|
||||
st.sf0ExpGcode0, st.sf0FracGcode0 = gpu.expGcode0, gpu.fracGcode0
|
||||
fc, ec, cgFrac, cgExp := calcFiltEnergies(mode, xn, xn2, y1, y2, r.gCoeff[:])
|
||||
st.sf0FracCoeff, st.sf0ExpCoeff = fc, ec
|
||||
st.sf0ExpTargetEn, st.sf0FracTargetEn = calcTargetEnergy(xn)
|
||||
st.predUnq.mr475UpdateUnqPred(st.sf0ExpGcode0, st.sf0FracGcode0, cgExp, cgFrac)
|
||||
|
||||
// tentative synthesis with the unquantized optimum gains
|
||||
gainCode := shl(cgFrac, cgExp+1)
|
||||
iSubfrSf0 = iSubfr
|
||||
copy(xnSf0[:], xn)
|
||||
copy(y2Sf0[:], y2)
|
||||
copy(codeSf0[:], code)
|
||||
T0Sf0, T0fracSf0 = r.T0, r.T0frac
|
||||
subframePostProc(st.oldSpeech[:], cSpeechOff, mode, iSubfr, r.gainPit, gainCode,
|
||||
aqSub, synth, xn, code, y1, y2, memSynSave[:], st.memErr[:], memW0Save[:],
|
||||
st.oldExc[:], cExcOff, &st.sharp)
|
||||
st.sharp = sharpSave
|
||||
continue
|
||||
}
|
||||
|
||||
// odd subframe: joint gain quantization for the pair
|
||||
gpu := st.predUnq.gcPred(mode, code)
|
||||
fc, ec, _, _ := calcFiltEnergies(mode, xn, xn2, y1, y2, r.gCoeff[:])
|
||||
tEnExp, tEnFrac := calcTargetEnergy(xn)
|
||||
idx, sf0gp, sf0gc, sf1gp, sf1gc := st.mr475GainQuant(code, gpu.expGcode0, gpu.fracGcode0,
|
||||
ec[:], fc[:], tEnExp, tEnFrac, r.gpLimit)
|
||||
prm[gainIdxPos] = idx
|
||||
gainPitSf0, gainCodeSf0 = sf0gp, sf0gc
|
||||
|
||||
// redo the even subframe's final synthesis with the quantized gains
|
||||
st.memErr = memErrSave
|
||||
predLt(st.oldExc[:], cExcOff+iSubfrSf0, T0Sf0, T0fracSf0, cL_SUBFR, 1)
|
||||
convolve(st.oldExc[cExcOff+iSubfrSf0:], h1Sf0[:], y1, cL_SUBFR)
|
||||
subframePostProc(st.oldSpeech[:], cSpeechOff, mode, iSubfrSf0, gainPitSf0, gainCodeSf0,
|
||||
azQ[(subfrNr-1)*cMP1:], synth, xnSf0[:], codeSf0[:], y1, y2Sf0[:],
|
||||
st.memSyn[:], st.memErr[:], st.memW0[:], st.oldExc[:], cExcOff, &sharpSave)
|
||||
|
||||
// redo the odd subframe's analysis + synthesis with the final memories
|
||||
subframePreProc(mode, aSub, aqSub, st.oldSpeech[:], cSpeechOff+iSubfr,
|
||||
st.memErr[:], st.memW0[:], st.oldExc[excBase:], h1, xn, res, errSig)
|
||||
predLt(st.oldExc[:], excBase, r.T0, r.T0frac, cL_SUBFR, 1)
|
||||
convolve(st.oldExc[excBase:], h1, y1, cL_SUBFR)
|
||||
subframePostProc(st.oldSpeech[:], cSpeechOff, mode, iSubfr, sf1gp, sf1gc,
|
||||
aqSub, synth, xn, code, y1, y2, st.memSyn[:], st.memErr[:], st.memW0[:],
|
||||
st.oldExc[:], cExcOff, &st.sharp)
|
||||
}
|
||||
}
|
||||
|
||||
// olPitch runs the open-loop pitch over the weighted-speech buffer for the
|
||||
// half-frame at frameOffset.
|
||||
func (st *coderState) olPitch(mode, frameOffset int) int16 {
|
||||
idx := 0
|
||||
if frameOffset != 0 {
|
||||
idx = 1
|
||||
}
|
||||
if mode == dMR102 {
|
||||
// weighted open-loop pitch with median/gain-flag adaptation
|
||||
return st.pitWght.pitchOlWgh(st.oldWsp[:], cPIT_MAX+frameOffset, cPIT_MIN, cPIT_MAX,
|
||||
cL_FRAME_BY2, st.oldLags[:], st.olGainFlg[:], idx)
|
||||
}
|
||||
pitMin := int16(cPIT_MIN)
|
||||
if mode == dMR122 {
|
||||
pitMin = cPIT_MIN_MR122
|
||||
}
|
||||
return pitchOl(mode, st.oldWsp[:], cPIT_MAX+frameOffset, int(pitMin), cPIT_MAX, cL_FRAME_BY2)
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package amrnb
|
||||
|
||||
// Sign-weighted impulse-response autocorrelation matrix, ported from
|
||||
// opencore-amrnb cor_h.cpp. corH builds rr[i][j] (flattened, row-major, size
|
||||
// L_CODE*L_CODE): the diagonal holds the truncated energy of the weighted
|
||||
// impulse response (used to place a pulse at position i), and the off-diagonal
|
||||
// holds the sign-weighted cross-correlation between candidate pulse positions
|
||||
// i and j. This matrix drives the per-mode algebraic codebook pulse searches.
|
||||
// The reference's exact incremental Q15 roundings and pointer walk are
|
||||
// preserved (bit-exact).
|
||||
|
||||
// corH fills the flattened rr (length cL_CODE*cL_CODE) from the weighted impulse
|
||||
// response h and the per-position signs. Mirrors cor_h.
|
||||
func corH(h, sign, rr []int16) {
|
||||
var h2 [cL_CODE]int16
|
||||
|
||||
// energy of h, and the scaling of h into h2
|
||||
s := int32(1)
|
||||
for i := 0; i < cL_CODE; i++ {
|
||||
s += int32(h[i]) * int32(h[i])
|
||||
}
|
||||
s <<= 1
|
||||
if s < 0 { // overflow -> halve
|
||||
for i := 0; i < cL_CODE; i++ {
|
||||
h2[i] = h[i] >> 1
|
||||
}
|
||||
} else {
|
||||
s >>= 1
|
||||
s = invSqrt(s)
|
||||
var dec int16
|
||||
if s < 0x00ffffff {
|
||||
dec = int16(((s >> 9) * 32440) >> 15)
|
||||
} else {
|
||||
dec = 32440 // 0.99
|
||||
}
|
||||
for i := 0; i < cL_CODE; i++ {
|
||||
h2[i] = int16((int32(h[i])*int32(dec) + 0x20) >> 6)
|
||||
}
|
||||
}
|
||||
|
||||
const L = cL_CODE
|
||||
|
||||
// diagonal: rr[L-1-m][L-1-m] = sum_{k=0..m} h2[k]^2
|
||||
s = 0
|
||||
p := 0
|
||||
rr1 := (L-1)*L + (L - 1)
|
||||
for i := L >> 1; i != 0; i-- {
|
||||
t := int32(h2[p])
|
||||
p++
|
||||
s += t * t
|
||||
rr[rr1] = int16((s + 0x4000) >> 15)
|
||||
rr1 -= L + 1
|
||||
t = int32(h2[p])
|
||||
p++
|
||||
s += t * t
|
||||
rr[rr1] = int16((s + 0x4000) >> 15)
|
||||
rr1 -= L + 1
|
||||
}
|
||||
|
||||
// off-diagonal: sign-weighted cross-correlation at each distance dec
|
||||
pRrRef1 := (L - 1) * L
|
||||
for dec := 1; dec < L; dec += 2 {
|
||||
rr1 := pRrRef1 + (L - 1 - dec) // &rr[L-1][L-1-dec]
|
||||
rr2 := (L-1-dec)*L + (L - 1) // &rr[L-1-dec][L-1]
|
||||
rr3 := (L-1-(dec+1))*L + (L - 1)
|
||||
|
||||
var s2 int32
|
||||
s = 0
|
||||
pSign1 := L - 1
|
||||
pSign2 := L - 1 - dec
|
||||
ph2 := 0
|
||||
ph := dec
|
||||
|
||||
for i := L - dec - 1; i != 0; i-- {
|
||||
s += int32(h2[ph2]) * int32(h2[ph])
|
||||
ph++
|
||||
s2 += int32(h2[ph2]) * int32(h2[ph])
|
||||
ph2++
|
||||
tmp1 := int16((s + 0x4000) >> 15)
|
||||
tmp11 := int16((s2 + 0x4000) >> 15)
|
||||
tmp2 := int16((int32(sign[pSign1]) * int32(sign[pSign2])) >> 15)
|
||||
pSign2--
|
||||
tmp22 := int16((int32(sign[pSign1]) * int32(sign[pSign2])) >> 15)
|
||||
pSign1--
|
||||
|
||||
rr[rr2] = int16((int32(tmp1) * int32(tmp2)) >> 15)
|
||||
rr[rr1] = rr[rr2]
|
||||
rr1--
|
||||
rr[rr1] = int16((int32(tmp11) * int32(tmp22)) >> 15)
|
||||
rr[rr3] = rr[rr1]
|
||||
|
||||
rr1 -= L
|
||||
rr2 -= L + 1
|
||||
rr3 -= L + 1
|
||||
}
|
||||
|
||||
s += int32(h2[ph2]) * int32(h2[ph])
|
||||
tmp1 := int16((s + 0x4000) >> 15)
|
||||
tmp2 := int16((int32(sign[pSign1]) * int32(sign[pSign2])) >> 15)
|
||||
rr[rr1] = int16((int32(tmp1) * int32(tmp2)) >> 15)
|
||||
rr[rr2] = rr[rr1]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package amrnb
|
||||
|
||||
// Encoder analysis-by-synthesis filter kernels, ported from opencore-amrnb
|
||||
// convolve.cpp. convolve computes the (truncated) lower-triangular convolution
|
||||
// y[n] = sum_{i=0..n} x[i]·h[n-i] >> 12, used throughout the closed-loop pitch
|
||||
// and algebraic codebook searches to filter an excitation by the weighted
|
||||
// synthesis impulse response. The reference accumulates in non-saturating int32,
|
||||
// so a straightforward double loop is bit-exact.
|
||||
func convolve(x, h, y []int16, L int) {
|
||||
xf := x[:L] // hoist bounds: i<=n<L and n-i in [0,n]
|
||||
hf := h[:L]
|
||||
for n := 0; n < L; n++ {
|
||||
var s int32
|
||||
hn := hf[:n+1] // h[n-i] == hn[n-i], index in [0,n]
|
||||
for i := 0; i <= n; i++ {
|
||||
s += int32(xf[i]) * int32(hn[n-i])
|
||||
}
|
||||
y[n] = int16(s >> 12)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,244 @@
|
||||
package amrnb
|
||||
|
||||
// Encoder LP analysis chain, ported from opencore-amrnb pre_proc.cpp
|
||||
// (Pre_Process), autocorr.cpp (Autocorr), lag_wind.cpp (Lag_window) and
|
||||
// levinson.cpp (Levinson), plus the 32-bit operators they need (Mpy_32, Div_32,
|
||||
// L_abs). Together these turn 8 kHz PCM into the order-10 LP coefficients A(z):
|
||||
// input high-pass + scaling, windowed autocorrelation, lag-window bandwidth
|
||||
// expansion, then the Levinson-Durbin recursion. Bit-exact with the reference.
|
||||
|
||||
// L_abs returns the saturated 32-bit absolute value (|MIN_32| -> MAX_32).
|
||||
// Mirrors L_abs.
|
||||
func L_abs(x int32) int32 {
|
||||
if x == minInt32 {
|
||||
return maxInt32
|
||||
}
|
||||
if x < 0 {
|
||||
return -x
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// mpy_32 multiplies two 32-bit values given in (hi,lo) double-precision form.
|
||||
// Mirrors the generic Mpy_32.
|
||||
func mpy_32(hi1, lo1, hi2, lo2 int16) int32 {
|
||||
L := L_mult(hi1, hi2)
|
||||
L = L_add(L, ((int32(hi1)*int32(lo2))>>15)<<1)
|
||||
L = L_add(L, ((int32(lo1)*int32(hi2))>>15)<<1)
|
||||
return L
|
||||
}
|
||||
|
||||
// div_32 divides a 32-bit numerator by a 32-bit denominator (given as hi,lo).
|
||||
// Mirrors Div_32.
|
||||
func div_32(num int32, denomHi, denomLo int16) int32 {
|
||||
approx := div_s(0x3fff, denomHi)
|
||||
result := mpy32_16(denomHi, denomLo, approx)
|
||||
result = 0x7fffffff - result
|
||||
hi, lo := L_Extract(result)
|
||||
result = mpy32_16(hi, lo, approx)
|
||||
hi, lo = L_Extract(result)
|
||||
nHi, nLo := L_Extract(num)
|
||||
result = mpy_32(nHi, nLo, hi, lo)
|
||||
return L_shl(result, 2)
|
||||
}
|
||||
|
||||
// preProcessState holds the encoder input high-pass biquad memory.
|
||||
type preProcessState struct {
|
||||
x0, x1 int16
|
||||
y1hi, y1lo, y2hi, y2lo int16
|
||||
}
|
||||
|
||||
// process applies the input high-pass filter (with 0.5 scaling) in place over
|
||||
// lg samples. Mirrors Pre_Process.
|
||||
func (st *preProcessState) process(signal []int16, lg int) {
|
||||
xn2 := st.x1
|
||||
xn1 := st.x0
|
||||
for i := 0; i < lg; i++ {
|
||||
L := int32(st.y1hi) * 7807
|
||||
L += (int32(st.y1lo) * 7807) >> 15
|
||||
L += int32(st.y2hi) * -3733
|
||||
st.y2hi = st.y1hi
|
||||
L += (int32(st.y2lo) * -3733) >> 15
|
||||
st.y2lo = st.y1lo
|
||||
L += int32(xn2) * 1899
|
||||
xn2 = xn1
|
||||
L += int32(xn1) * -3798
|
||||
xn1 = signal[i]
|
||||
L += int32(xn1) * 1899
|
||||
|
||||
signal[i] = int16((L + 0x800) >> 12)
|
||||
st.y1hi = int16(L >> 12)
|
||||
st.y1lo = int16((L << 3) - (int32(st.y1hi) << 15))
|
||||
}
|
||||
st.x1 = xn2
|
||||
st.x0 = xn1
|
||||
}
|
||||
|
||||
// autocorr windows x with wind and computes the order-m autocorrelation into
|
||||
// (rh,rl) double precision, returning the normalization shift applied. Mirrors
|
||||
// Autocorr.
|
||||
func autocorr(x []int16, m int, rh, rl, wind []int16) int16 {
|
||||
var y [cL_WINDOW]int16
|
||||
|
||||
var sum int32
|
||||
overflow := false
|
||||
b := 0
|
||||
for ; b < cL_WINDOW; b++ {
|
||||
temp := int16((int32(x[b])*int32(wind[b]) + 0x4000) >> 15)
|
||||
y[b] = temp
|
||||
sum += (int32(temp) * int32(temp)) << 1
|
||||
if sum < 0 {
|
||||
overflow = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
overflShft := int16(0)
|
||||
if overflow {
|
||||
for k := b + 1; k < cL_WINDOW; k++ {
|
||||
y[k] = int16((int32(x[k])*int32(wind[k]) + 0x4000) >> 15)
|
||||
}
|
||||
for {
|
||||
overflShft += 4
|
||||
sum = 0
|
||||
for k := 0; k < cL_WINDOW; k++ {
|
||||
t := y[k] >> 2
|
||||
y[k] = t
|
||||
sum += (int32(t) * int32(t)) << 1
|
||||
}
|
||||
if sum > 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sum++ // avoid all-zeros
|
||||
norm := norm_l(sum)
|
||||
sum <<= uint(norm)
|
||||
rh[0] = int16(sum >> 16)
|
||||
rl[0] = int16((sum >> 1) - (int32(rh[0]) << 15))
|
||||
|
||||
for i := 1; i <= m; i++ {
|
||||
// sum_{n=i}^{W-1} y[n]·y[n-i] = sum_k y[i+k]·y[k] (wrapping int32) via firDot
|
||||
s := firDot(y[i:cL_WINDOW], y[:cL_WINDOW-i])
|
||||
s <<= uint(norm + 1)
|
||||
rh[i] = int16(s >> 16)
|
||||
rl[i] = int16((s >> 1) - (int32(rh[i]) << 15))
|
||||
}
|
||||
|
||||
return norm - overflShft
|
||||
}
|
||||
|
||||
// lagWindow applies the lag-window bandwidth expansion to the autocorrelation
|
||||
// in place. Mirrors Lag_window.
|
||||
func lagWindow(m int, rh, rl []int16) {
|
||||
for i := 1; i <= m; i++ {
|
||||
x := mpy_32(rh[i], rl[i], lag_h[i-1], lag_l[i-1])
|
||||
rh[i] = int16(x >> 16)
|
||||
rl[i] = int16((x >> 1) - (int32(rh[i]) << 15))
|
||||
}
|
||||
}
|
||||
|
||||
// levinsonState carries the last stable A(z) for the unstable-filter fallback.
|
||||
type levinsonState struct {
|
||||
oldA [cMP1]int16
|
||||
}
|
||||
|
||||
// levinson runs the Levinson-Durbin recursion on the (rh,rl) autocorrelation,
|
||||
// producing order-10 LP coefficients A[0:M+1] and the first 4 reflection
|
||||
// coefficients rc[0:4]. Mirrors Levinson.
|
||||
func (st *levinsonState) levinson(rh, rl, a, rc []int16) {
|
||||
var ah, al, anh, anl [cMP1]int16
|
||||
|
||||
t1 := (int32(rh[1]) << 16) + (int32(rl[1]) << 1)
|
||||
t2 := L_abs(t1)
|
||||
t0 := div_32(t2, rh[0], rl[0]) // R[1]/R[0]
|
||||
if t1 > 0 {
|
||||
t0 = L_negate(t0)
|
||||
}
|
||||
kh, kl := L_Extract(t0)
|
||||
rc[0] = round_(t0)
|
||||
|
||||
t0 >>= 4
|
||||
ah[1] = int16(t0 >> 16)
|
||||
al[1] = int16((t0 >> 1) - (int32(ah[1]) << 15))
|
||||
|
||||
t0 = mpy_32(kh, kl, kh, kl) // K*K
|
||||
t0 = L_abs(t0)
|
||||
t0 = 0x7fffffff - t0 // 1 - K*K
|
||||
hi, lo := L_Extract(t0)
|
||||
t0 = mpy_32(rh[0], rl[0], hi, lo) // Alpha
|
||||
alpExp := norm_l(t0)
|
||||
t0 = t0 << uint(alpExp)
|
||||
alpH := int16(t0 >> 16)
|
||||
alpL := int16((t0 >> 1) - (int32(alpH) << 15))
|
||||
|
||||
for i := 2; i <= cM; i++ {
|
||||
t0 = 0
|
||||
for j := 1; j < i; j++ {
|
||||
t0 += (int32(rh[j]) * int32(al[i-j])) >> 15
|
||||
t0 += (int32(rl[j]) * int32(ah[i-j])) >> 15
|
||||
t0 += int32(rh[j]) * int32(ah[i-j])
|
||||
}
|
||||
t0 <<= 5
|
||||
t1 = (int32(rh[i]) << 16) + (int32(rl[i]) << 1)
|
||||
t0 += t1
|
||||
|
||||
t1 = L_abs(t0)
|
||||
t2 = div_32(t1, alpH, alpL)
|
||||
if t0 > 0 {
|
||||
t2 = L_negate(t2)
|
||||
}
|
||||
t2 = L_shl(t2, alpExp)
|
||||
kh = int16(t2 >> 16)
|
||||
kl = int16((t2 >> 1) - (int32(kh) << 15))
|
||||
|
||||
if i < 5 {
|
||||
rc[i-1] = int16((t2 + 0x8000) >> 16)
|
||||
}
|
||||
if abs_s(kh) > 32750 { // unstable filter -> reuse last A(z)
|
||||
copy(a[:cMP1], st.oldA[:])
|
||||
for k := 0; k < 4; k++ {
|
||||
rc[k] = 0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
for j := 1; j < i; j++ {
|
||||
t0 = (int32(kh) * int32(al[i-j])) >> 15
|
||||
t0 += (int32(kl) * int32(ah[i-j])) >> 15
|
||||
t0 += int32(kh) * int32(ah[i-j])
|
||||
t0 += (int32(ah[j]) << 15) + int32(al[j])
|
||||
anh[j] = int16(t0 >> 15)
|
||||
anl[j] = int16(t0 - (int32(anh[j]) << 15))
|
||||
}
|
||||
anh[i] = int16(t2 >> 20)
|
||||
anl[i] = int16((t2 >> 5) - (int32(anh[i]) << 15))
|
||||
|
||||
t0 = mpy_32(kh, kl, kh, kl) // K*K
|
||||
t0 = L_abs(t0)
|
||||
t0 = 0x7fffffff - t0 // 1 - K*K
|
||||
hi = int16(t0 >> 16)
|
||||
lo = int16((t0 >> 1) - (int32(hi) << 15))
|
||||
|
||||
t0 = (int32(alpH) * int32(lo)) >> 15
|
||||
t0 += (int32(alpL) * int32(hi)) >> 15
|
||||
t0 += int32(alpH) * int32(hi)
|
||||
t0 <<= 1
|
||||
jn := norm_l(t0)
|
||||
t0 = t0 << uint(jn)
|
||||
alpH = int16(t0 >> 16)
|
||||
alpL = int16((t0 >> 1) - (int32(alpH) << 15))
|
||||
alpExp += jn
|
||||
|
||||
copy(ah[1:1+i], anh[1:1+i])
|
||||
copy(al[1:1+i], anl[1:1+i])
|
||||
}
|
||||
|
||||
a[0] = 4096
|
||||
for i := 1; i <= cM; i++ {
|
||||
t0 = (int32(ah[i]) << 15) + int32(al[i])
|
||||
a[i] = int16((t0 + 0x2000) >> 14)
|
||||
st.oldA[i] = a[i]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package amrnb
|
||||
|
||||
// Encoder LSP analysis/quantization wrapper, ported from opencore-amrnb lsp.cpp
|
||||
// (lsp). Per frame it converts the analysis A(z) to LSPs (azLsp), quantizes them
|
||||
// (qPlsf3/qPlsf5), and interpolates both the unquantized LP filters (az, for the
|
||||
// perceptual weighting) and the quantized ones (azQ, for synthesis) across the
|
||||
// four subframes, returning the LSF codebook indices. Bit-exact with the
|
||||
// reference.
|
||||
|
||||
// lspEncState holds the encoder's LSP predictor memories.
|
||||
type lspEncState struct {
|
||||
lspOld [cM]int16
|
||||
lspOldQ [cM]int16
|
||||
q qPlsfState
|
||||
}
|
||||
|
||||
func (st *lspEncState) reset() {
|
||||
copy(st.lspOld[:], lsp_init_data[:cM])
|
||||
copy(st.lspOldQ[:], lsp_init_data[:cM])
|
||||
st.q.reset()
|
||||
}
|
||||
|
||||
// lsp processes one frame's LP analysis. az holds the unquantized A(z) with the
|
||||
// per-window filters already placed (A_mid at [MP1] for MR122, A_new at [3*MP1]);
|
||||
// on return az and azQ hold the interpolated unquantized/quantized filters for
|
||||
// all four subframes. The LSF indices are written to anap; the count is
|
||||
// returned. Mirrors lsp.
|
||||
func (st *lspEncState) lsp(mode int, az, azQ, anap []int16) int {
|
||||
var lspNew [cM]int16
|
||||
if mode == dMR122 {
|
||||
var lspMid, lspMidQ, lspNewQ [cM]int16
|
||||
azLsp(az[cMP1:], lspMid[:], st.lspOld[:])
|
||||
azLsp(az[3*cMP1:], lspNew[:], lspMid[:])
|
||||
intLpc1and3_2(st.lspOld[:], lspMid[:], lspNew[:], az)
|
||||
|
||||
idx := st.q.qPlsf5(lspMid[:], lspNew[:], lspMidQ[:], lspNewQ[:])
|
||||
intLpc1and3(st.lspOldQ[:], lspMidQ[:], lspNewQ[:], azQ)
|
||||
copy(anap[:5], idx[:])
|
||||
copy(st.lspOldQ[:], lspNewQ[:])
|
||||
copy(st.lspOld[:], lspNew[:])
|
||||
return 5
|
||||
}
|
||||
|
||||
var lspNewQ [cM]int16
|
||||
azLsp(az[3*cMP1:], lspNew[:], st.lspOld[:])
|
||||
intLpc1to3_2(st.lspOld[:], lspNew[:], az)
|
||||
|
||||
idx := st.q.qPlsf3(mode, lspNew[:], lspNewQ[:])
|
||||
intLpc1to3(st.lspOldQ[:], lspNewQ[:], azQ)
|
||||
copy(anap[:3], idx[:])
|
||||
copy(st.lspOldQ[:], lspNewQ[:])
|
||||
copy(st.lspOld[:], lspNew[:])
|
||||
return 3
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
package amrnb
|
||||
|
||||
// Open-loop pitch estimation, ported from opencore-amrnb pitch_ol.cpp
|
||||
// (Pitch_ol, Lag_max) and calc_cor.cpp (comp_corr). pitchOl scales the weighted
|
||||
// speech, computes its autocorrelation over the pitch-lag range, finds the best
|
||||
// lag in three sub-ranges, and selects among them favouring longer lags unless
|
||||
// a shorter lag's normalized correlation is significantly stronger. The DTX/VAD
|
||||
// tone-detection side path is omitted (dtx=0). Bit-exact with the reference for
|
||||
// the active-speech path.
|
||||
|
||||
const cTHRESHOLD = 27853 // 0.85, the open-loop lag-selection threshold
|
||||
|
||||
// lagMax finds the lag in [lagMin, lagMax] with maximum correlation and returns
|
||||
// it together with its normalized correlation. Mirrors Lag_max (dtx=0 path).
|
||||
func lagMax(corr []int32, scaled []int16, pitMax int, scalFac, scalFlag int16, Lframe, lagMax, lagMin int) (int16, int16) {
|
||||
max := int32(minInt32)
|
||||
pMax := int16(lagMax)
|
||||
for i := lagMax; i >= lagMin; i-- {
|
||||
if corr[i] >= max {
|
||||
max = corr[i]
|
||||
pMax = int16(i)
|
||||
}
|
||||
}
|
||||
|
||||
var t0 int32
|
||||
base := pitMax - int(pMax)
|
||||
for m := 0; m < Lframe; m++ {
|
||||
v := int32(scaled[base+m])
|
||||
t0 += v * v
|
||||
}
|
||||
t0 <<= 1
|
||||
t0 = invSqrt(t0)
|
||||
if scalFlag != 0 {
|
||||
if t0 > 0x3fffffff {
|
||||
t0 = maxInt32
|
||||
} else {
|
||||
t0 <<= 1
|
||||
}
|
||||
}
|
||||
|
||||
maxH := int16(max >> 16)
|
||||
maxL := int16((max >> 1) - (int32(maxH) << 15))
|
||||
enerH := int16(t0 >> 16)
|
||||
enerL := int16((t0 >> 1) - (int32(enerH) << 15))
|
||||
t0 = mpy_32(maxH, maxL, enerH, enerL)
|
||||
|
||||
var corMax int16
|
||||
if scalFlag != 0 {
|
||||
t0 = L_shr(t0, scalFac)
|
||||
if t0 > 0x0000FFFF {
|
||||
corMax = maxInt16
|
||||
} else if t0 < int32(-0x10000) {
|
||||
corMax = minInt16
|
||||
} else {
|
||||
corMax = int16(t0 >> 1)
|
||||
}
|
||||
} else {
|
||||
corMax = int16(t0)
|
||||
}
|
||||
return pMax, corMax
|
||||
}
|
||||
|
||||
// pitchOl returns the open-loop pitch lag for the weighted speech in
|
||||
// signal[off-pitMax : off+Lframe], using the given pitch-lag bounds and frame
|
||||
// length. Mirrors Pitch_ol (dtx=0). signal[off] is the current frame start.
|
||||
func pitchOl(mode int, signal []int16, off, pitMin, pitMax, Lframe int) int16 {
|
||||
// energy of signal[-pitMax .. Lframe-1]
|
||||
var t0 int32
|
||||
overflow := false
|
||||
for i := -pitMax; i < Lframe; i++ {
|
||||
v := int32(signal[off+i])
|
||||
t0 += (v * v) << 1
|
||||
if t0 < 0 {
|
||||
t0 = maxInt32
|
||||
overflow = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
n := pitMax + Lframe
|
||||
var scaledArr [cPIT_MAX + cL_FRAME]int16 // stack: max pitMax+Lframe
|
||||
scaled := scaledArr[:n]
|
||||
var scalFac int16
|
||||
switch {
|
||||
case overflow: // t0 == MAX_32
|
||||
for k := 0; k < n; k++ {
|
||||
scaled[k] = int16(int32(signal[off-pitMax+k]) >> 3)
|
||||
}
|
||||
scalFac = 3
|
||||
case t0 < 1048576:
|
||||
for k := 0; k < n; k++ {
|
||||
scaled[k] = int16(int32(signal[off-pitMax+k]) << 3)
|
||||
}
|
||||
scalFac = -3
|
||||
default:
|
||||
for k := 0; k < n; k++ {
|
||||
scaled[k] = signal[off-pitMax+k]
|
||||
}
|
||||
scalFac = 0
|
||||
}
|
||||
|
||||
// correlation by lag: corr[lag] = 2 * sum_m scaled[pitMax+m]·scaled[pitMax+m-lag].
|
||||
// With the fixed window coef = scaled[pitMax:pitMax+Lframe] this is one sliding
|
||||
// FIR over scaled: dst[pitMax-lag] = sum_m scaled[pitMax-lag+m]·coef[m] equals
|
||||
// corr[lag]>>1. firRaw (AVX2) vectorises it; the wrapping int32 accumulation
|
||||
// makes the lane-parallel order bit-identical.
|
||||
var corrArr [cPIT_MAX + 1]int32 // stack
|
||||
corr := corrArr[:pitMax+1]
|
||||
var dstArr [cPIT_MAX + 1]int32
|
||||
dst := dstArr[:pitMax-pitMin+1]
|
||||
firRaw(dst, scaled, scaled[pitMax:pitMax+Lframe])
|
||||
for lag := pitMin; lag <= pitMax; lag++ {
|
||||
corr[lag] = dst[pitMax-lag] << 1
|
||||
}
|
||||
|
||||
scalFlag := int16(0)
|
||||
if mode == dMR122 {
|
||||
scalFlag = 1
|
||||
}
|
||||
|
||||
j := pitMin << 2
|
||||
pMax1, max1 := lagMax(corr, scaled, pitMax, scalFac, scalFlag, Lframe, pitMax, j)
|
||||
i := j - 1
|
||||
j = pitMin << 1
|
||||
pMax2, max2 := lagMax(corr, scaled, pitMax, scalFac, scalFlag, Lframe, i, j)
|
||||
i = j - 1
|
||||
pMax3, max3 := lagMax(corr, scaled, pitMax, scalFac, scalFlag, Lframe, i, pitMin)
|
||||
|
||||
if int16((int32(max1)*cTHRESHOLD)>>15) < max2 {
|
||||
max1 = max2
|
||||
pMax1 = pMax2
|
||||
}
|
||||
if int16((int32(max1)*cTHRESHOLD)>>15) < max3 {
|
||||
pMax1 = pMax3
|
||||
}
|
||||
return pMax1
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
package amrnb
|
||||
|
||||
// Weighted open-loop pitch analysis for MR102, ported from opencore-amrnb
|
||||
// p_ol_wgh.cpp (Pitch_ol_wgh, Lag_max) and calc_cor.cpp (comp_corr). Unlike the
|
||||
// plain Pitch_ol used by the other modes, MR102 weights the lag correlations by
|
||||
// a fixed curve and, when the previous frame tracked pitch well, by a window
|
||||
// centred on the running median lag — then adapts whether to keep weighting.
|
||||
// It also emits a per-half-frame gain flag that gates the median update and the
|
||||
// closed-loop lag history. Bit-exact with the reference (non-DTX path).
|
||||
|
||||
// pitchOLWghtState is the weighted open-loop pitch state. Mirrors
|
||||
// pitchOLWghtState.
|
||||
type pitchOLWghtState struct {
|
||||
oldT0Med int16 // running median of past lags
|
||||
adaW int16 // adaptive weighting factor, Q15
|
||||
wghtFlg int16 // whether the median-window weighting is applied
|
||||
}
|
||||
|
||||
func (st *pitchOLWghtState) reset() {
|
||||
st.oldT0Med = 40
|
||||
st.adaW = 0
|
||||
st.wghtFlg = 0
|
||||
}
|
||||
|
||||
// compCorr computes corr[-i] = 2·Σ_j sig[j]·sig[j-i] (wrapping int32) for every
|
||||
// lag i in [pitMin, pitMax], where corr is indexed corr[corrOff-i]. Mirrors
|
||||
// comp_corr.
|
||||
func compCorr(sig []int16, sigOff, Lframe, pitMax, pitMin int, corr []int32, corrOff int) {
|
||||
// corr[corrOff-i] = 2·sum_j sig[sigOff+j]·sig[sigOff+j-i]. With the fixed
|
||||
// window coef = sig[sigOff:sigOff+Lframe] over x = sig[sigOff-pitMax:], this
|
||||
// is one sliding FIR: dst[pitMax-i] = sum_j sig[sigOff-i+j]·coef[j] equals
|
||||
// corr[corrOff-i]>>1. firRaw (AVX2) vectorises it, bit-identically (wrapping).
|
||||
var dstArr [cPIT_MAX + 1]int32
|
||||
dst := dstArr[:pitMax-pitMin+1]
|
||||
firRaw(dst, sig[sigOff-pitMax:], sig[sigOff:sigOff+Lframe])
|
||||
for i := pitMin; i <= pitMax; i++ {
|
||||
corr[corrOff-i] = dst[pitMax-i] << 1
|
||||
}
|
||||
}
|
||||
|
||||
// lagMaxWght finds the best (most weighted-correlated) lag and the open-loop
|
||||
// gain flag. Mirrors the weighted Lag_max (non-DTX path: cor_max is unused).
|
||||
func lagMaxWght(corr []int32, corrOff int, sig []int16, sigOff int, Lframe, lagMax, lagMin, oldLag, wghtFlg int16) (pMax, gainFlg int16) {
|
||||
wwi := 250 // &corrweight[250]
|
||||
wei := 123 + int(lagMax) - int(oldLag) // &corrweight[123 + lag_max - old_lag]
|
||||
max := int32(-2147483648) // MIN_32
|
||||
pMax = lagMax
|
||||
for i := lagMax; i >= lagMin; i-- {
|
||||
hi, lo := L_Extract(corr[corrOff-int(i)])
|
||||
t0 := mpy32_16(hi, lo, corrweight[wwi])
|
||||
wwi--
|
||||
if wghtFlg > 0 {
|
||||
hi, lo = L_Extract(t0)
|
||||
t0 = mpy32_16(hi, lo, corrweight[wei])
|
||||
wei--
|
||||
}
|
||||
if t0 >= max {
|
||||
max = t0
|
||||
pMax = i
|
||||
}
|
||||
}
|
||||
|
||||
var t0, t1 int32
|
||||
for j := 0; j < int(Lframe); j++ {
|
||||
a := sig[sigOff+j]
|
||||
b := sig[sigOff+j-int(pMax)]
|
||||
t0 = L_mac(t0, a, b)
|
||||
t1 = L_mac(t1, b, b)
|
||||
}
|
||||
temp := round_(t1)
|
||||
t1 = L_msu(t0, temp, 13107) // t0 - round(t1)*0.4
|
||||
gainFlg = round_(t1)
|
||||
return
|
||||
}
|
||||
|
||||
// pitchOlWgh runs the MR102 weighted open-loop pitch over one half-frame of the
|
||||
// weighted speech (sig[sigOff-pitMax : sigOff+Lframe]), updating the state and
|
||||
// the gain flag, and maintaining the median-lag history. Mirrors Pitch_ol_wgh
|
||||
// (non-DTX). idx selects the half-frame (0 or 1).
|
||||
func (st *pitchOLWghtState) pitchOlWgh(sig []int16, sigOff, pitMin, pitMax, Lframe int, oldLags, olGainFlg []int16, idx int) int16 {
|
||||
// energy of the (history + frame) signal, to choose the scaling
|
||||
var t0 int32
|
||||
for i := -pitMax; i < Lframe; i++ {
|
||||
t0 = L_mac(t0, sig[sigOff+i], sig[sigOff+i])
|
||||
}
|
||||
|
||||
// scaled signal occupies scal[pitMax-pitMax : pitMax+Lframe]; use a buffer
|
||||
// with the same [pitMax | Lframe] layout as the input.
|
||||
var scalArr [cPIT_MAX + cL_FRAME]int16 // stack
|
||||
scal := scalArr[:pitMax+Lframe]
|
||||
scalOff := pitMax
|
||||
switch {
|
||||
case t0 == maxInt32:
|
||||
for i := -pitMax; i < Lframe; i++ {
|
||||
scal[scalOff+i] = shr(sig[sigOff+i], 3)
|
||||
}
|
||||
case t0 < 1048576:
|
||||
for i := -pitMax; i < Lframe; i++ {
|
||||
scal[scalOff+i] = shl(sig[sigOff+i], 3)
|
||||
}
|
||||
default:
|
||||
for i := -pitMax; i < Lframe; i++ {
|
||||
scal[scalOff+i] = sig[sigOff+i]
|
||||
}
|
||||
}
|
||||
|
||||
var corrArr [cPIT_MAX + 1]int32 // stack
|
||||
corr := corrArr[:pitMax+1]
|
||||
corrOff := pitMax
|
||||
compCorr(scal, scalOff, Lframe, pitMax, pitMin, corr, corrOff)
|
||||
|
||||
pMax1, gainFlg := lagMaxWght(corr, corrOff, scal, scalOff, int16(Lframe),
|
||||
int16(pitMax), int16(pitMin), st.oldT0Med, st.wghtFlg)
|
||||
olGainFlg[idx] = gainFlg
|
||||
|
||||
if olGainFlg[idx] > 0 {
|
||||
for i := 4; i > 0; i-- {
|
||||
oldLags[i] = oldLags[i-1]
|
||||
}
|
||||
oldLags[0] = pMax1
|
||||
st.oldT0Med = gmedN(oldLags, 5)
|
||||
st.adaW = 32767
|
||||
} else {
|
||||
st.oldT0Med = pMax1
|
||||
st.adaW = mult(st.adaW, 29491) // ada_w *= 0.9
|
||||
}
|
||||
|
||||
if st.adaW < 9830 { // < 0.3
|
||||
st.wghtFlg = 0
|
||||
} else {
|
||||
st.wghtFlg = 1
|
||||
}
|
||||
return pMax1
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
package amrnb
|
||||
|
||||
// Pitch-lag encoding, ported from opencore-amrnb enc_lag3.cpp and enc_lag6.cpp.
|
||||
// encLag3/encLag6 map a (T0, T0_frac) closed-loop pitch lag to the index the
|
||||
// bitstream carries — the exact inverses of the decoder's decLag3/decLag6.
|
||||
// Bit-exact with the reference.
|
||||
|
||||
// encLag3 encodes a 1/3-resolution pitch lag. deltaFlag==0 selects the 1st/3rd
|
||||
// subframe (absolute); otherwise the lag is coded relative to T0_min (or, with
|
||||
// flag4, the 4-bit scheme). Mirrors Enc_lag3.
|
||||
func encLag3(T0, T0frac, T0prev, T0min, T0max, deltaFlag, flag4 int16) int16 {
|
||||
var index, i, tmpInd, uplag, tmpLag, temp1, temp2 int16
|
||||
|
||||
if deltaFlag == 0 { // 1st or 3rd subframe
|
||||
if T0-85 <= 0 {
|
||||
index = (T0 << 1) + T0 - 58 + T0frac
|
||||
} else {
|
||||
index = T0 + 112
|
||||
}
|
||||
} else { // 2nd or 4th subframe
|
||||
if flag4 == 0 {
|
||||
i = T0 - T0min
|
||||
index = i + (i << 1) + 2 + T0frac
|
||||
} else {
|
||||
tmpLag = T0prev
|
||||
temp1 = tmpLag - T0min
|
||||
temp2 = temp1 - 5
|
||||
if temp2 > 0 {
|
||||
tmpLag = T0min + 5
|
||||
}
|
||||
temp1 = T0max - tmpLag
|
||||
temp2 = temp1 - 4
|
||||
if temp2 > 0 {
|
||||
tmpLag = T0max - 4
|
||||
}
|
||||
uplag = T0 + (T0 << 1) + T0frac
|
||||
i = tmpLag - 2
|
||||
tmpInd = i + (i << 1)
|
||||
temp1 = tmpInd - uplag
|
||||
if temp1 >= 0 {
|
||||
index = T0 - tmpLag + 5
|
||||
} else {
|
||||
i = tmpLag + 1
|
||||
i += i << 1
|
||||
if i > uplag {
|
||||
index = uplag - tmpInd + 3
|
||||
} else {
|
||||
index = T0 - tmpLag + 11
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return index
|
||||
}
|
||||
|
||||
// gPitch computes the optimal adaptive-codebook (pitch) gain in Q14, the ratio
|
||||
// <xn,y1>/<y1,y1> saturated to 1.2, where xn is the pitch target and y1 the
|
||||
// filtered adaptive excitation. It also returns the normalized correlations in
|
||||
// gCoeff for later gain quantization. Mirrors G_pitch (g_pitch.cpp).
|
||||
func gPitch(mode int, xn, y1, gCoeff []int16, Lsubfr int) int16 {
|
||||
// <y1,y1>
|
||||
var s int32
|
||||
for i := 0; i < Lsubfr; i++ {
|
||||
s += int32(y1[i]) * int32(y1[i])
|
||||
}
|
||||
var yy, expYy int16
|
||||
if s >= 0 && s < 0x40000000 {
|
||||
s = (s << 1) + 1
|
||||
expYy = norm_l(s)
|
||||
yy = round_(s << uint(expYy))
|
||||
} else {
|
||||
s = 0
|
||||
for i := 0; i < Lsubfr; i++ {
|
||||
tmp := y1[i] >> 2
|
||||
s += int32(tmp) * int32(tmp)
|
||||
}
|
||||
s = (s << 1) + 1
|
||||
expYy = norm_l(s)
|
||||
yy = round_(s << uint(expYy))
|
||||
expYy -= 4
|
||||
}
|
||||
|
||||
// <xn,y1> with overflow detection
|
||||
s = 0
|
||||
overflow := false
|
||||
for i := 0; i < Lsubfr; i++ {
|
||||
L := int32(xn[i]) * int32(y1[i])
|
||||
s1 := s
|
||||
s = s1 + L
|
||||
if (s1^L) > 0 && (s1^s) < 0 {
|
||||
overflow = true
|
||||
break
|
||||
}
|
||||
}
|
||||
var xy, expXy int16
|
||||
if !overflow {
|
||||
s = (s << 1) + 1
|
||||
expXy = norm_l(s)
|
||||
xy = round_(s << uint(expXy))
|
||||
} else {
|
||||
s = 0
|
||||
for i := 0; i < Lsubfr; i++ {
|
||||
L := int32(y1[i] >> 2)
|
||||
s += int32(xn[i]) * L
|
||||
}
|
||||
s = (s << 1) + 1
|
||||
expXy = norm_l(s)
|
||||
xy = round_(s << uint(expXy))
|
||||
expXy -= 4
|
||||
}
|
||||
|
||||
gCoeff[0] = yy
|
||||
gCoeff[1] = 15 - expYy
|
||||
gCoeff[2] = xy
|
||||
gCoeff[3] = 15 - expXy
|
||||
|
||||
if xy < 4 {
|
||||
return 0
|
||||
}
|
||||
xy >>= 1
|
||||
gain := div_s(xy, yy)
|
||||
gain = shr(gain, expXy-expYy)
|
||||
if gain > 19661 {
|
||||
gain = 19661
|
||||
}
|
||||
if mode == dMR122 {
|
||||
gain &^= 3
|
||||
}
|
||||
return gain
|
||||
}
|
||||
|
||||
// encLag6 encodes a 1/6-resolution pitch lag (MR122). deltaFlag==0 selects the
|
||||
// 1st/3rd subframe. Mirrors Enc_lag6.
|
||||
func encLag6(T0, T0frac, T0min, deltaFlag int16) int16 {
|
||||
var index, i int16
|
||||
if deltaFlag == 0 {
|
||||
if T0 <= 94 {
|
||||
i = (T0 << 3) - (T0 << 1) - 105
|
||||
index = i + T0frac
|
||||
} else {
|
||||
index = T0 + 368
|
||||
}
|
||||
} else {
|
||||
temp := T0 - T0min
|
||||
i = (temp << 3) - (temp << 1) + 3
|
||||
index = i + T0frac
|
||||
}
|
||||
return index
|
||||
}
|
||||
|
||||
// gCode computes the optimum innovation (fixed-codebook) gain
|
||||
// <xn2,y2>/<y2,y2> in Q1, used by the MR122 gain quantizer. Mirrors G_code.
|
||||
func gCode(xn2, y2 []int16) int16 {
|
||||
var s int32
|
||||
for i := 0; i < cL_SUBFR; i++ {
|
||||
s += int32(xn2[i]) * int32(y2[i]>>1)
|
||||
}
|
||||
s <<= 1
|
||||
expXy := norm_l(s + 1) // avoid the all-zeros case
|
||||
var xy int16
|
||||
if expXy < 17 {
|
||||
xy = int16(s >> uint(17-expXy))
|
||||
} else {
|
||||
xy = int16(s << uint(expXy-17))
|
||||
}
|
||||
if xy <= 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
s = 0
|
||||
for i := 0; i < cL_SUBFR; i++ {
|
||||
temp := y2[i] >> 1
|
||||
s += (int32(temp) * int32(temp)) >> 2
|
||||
}
|
||||
s <<= 3
|
||||
expYy := norm_l(s)
|
||||
var yy int16
|
||||
if expYy < 16 {
|
||||
yy = int16(s >> uint(16-expYy))
|
||||
} else {
|
||||
yy = int16(s << uint(expYy-16))
|
||||
}
|
||||
|
||||
gain := div_s(xy, yy)
|
||||
i := expXy + 5 - expYy // 15-1+9-18 = 5
|
||||
if i > 1 {
|
||||
gain >>= uint(i - 1)
|
||||
} else {
|
||||
gain <<= uint(1 - i)
|
||||
}
|
||||
return gain
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package amrnb
|
||||
|
||||
// Per-subframe target-signal and impulse-response setup, ported from
|
||||
// opencore-amrnb spreproc.cpp (subframePreProc). For each subframe it builds the
|
||||
// perceptually weighted LP filters A(z/γ1)/A(z/γ2), the weighted synthesis
|
||||
// impulse response h1, the LP residual (exc/res2), and the target signal xn for
|
||||
// the pitch search — feeding the closed-loop pitch and codebook searches. Uses
|
||||
// weightAi/synFilt/residu (all already ported). Bit-exact with the reference.
|
||||
|
||||
// perceptual-weighting spectral expansion factors (cod_amr.cpp).
|
||||
var gamma1 = [cM]int16{30802, 28954, 27217, 25584, 24049, 22606, 21250, 19975, 18777, 17650}
|
||||
var gamma1_12k2 = [cM]int16{29491, 26542, 23888, 21499, 19349, 17414, 15672, 14105, 12694, 11425}
|
||||
var gamma2 = [cM]int16{19661, 11797, 7078, 4247, 2548, 1529, 917, 550, 330, 198}
|
||||
|
||||
// subframePreProc computes, for one subframe:
|
||||
// - h1[0:L_SUBFR] the weighted synthesis impulse response,
|
||||
// - exc/res2 the LP residual,
|
||||
// - error the synthesis error,
|
||||
// - xn[0:L_SUBFR] the pitch-search target.
|
||||
//
|
||||
// a/aq are the unquantized/quantized LP coefficients for this subframe (M+1
|
||||
// each). speech is positioned so speech[speechOff-M : speechOff+L_SUBFR] is the
|
||||
// current subframe with history. memErr and memW0 are the synthesis-error and
|
||||
// weighting-filter memories (M each), read but not updated here. Mirrors
|
||||
// subframePreProc.
|
||||
func subframePreProc(mode int, a, aq, speech []int16, speechOff int, memErr, memW0 []int16, exc, h1, xn, res2, errSig []int16) {
|
||||
var ap1, ap2 [cMP1]int16
|
||||
g1 := gamma1[:]
|
||||
if mode == dMR122 || mode == dMR102 {
|
||||
g1 = gamma1_12k2[:]
|
||||
}
|
||||
weightAi(a, g1, ap1[:])
|
||||
weightAi(a, gamma2[:], ap2[:])
|
||||
|
||||
// h1 = impulse response of A(z/γ1) / (Aq(z)·A(z/γ2))
|
||||
var aiZero [cL_SUBFR]int16
|
||||
copy(aiZero[:cMP1], ap1[:cMP1]) // Ap1 then zeros
|
||||
zero := make([]int16, cM)
|
||||
synFilt(aq, aiZero[:], h1, cL_SUBFR, zero, false)
|
||||
for i := range zero {
|
||||
zero[i] = 0
|
||||
}
|
||||
synFilt(ap2[:], h1, h1, cL_SUBFR, zero, false)
|
||||
|
||||
// LP residual and synthesis error
|
||||
residu(aq, speech, speechOff, cL_SUBFR, res2)
|
||||
copy(exc[:cL_SUBFR], res2[:cL_SUBFR])
|
||||
|
||||
// error = synthesis of the residual (with error memory)
|
||||
memErrCopy := make([]int16, cM)
|
||||
copy(memErrCopy, memErr[:cM])
|
||||
synFilt(aq, exc, errSig, cL_SUBFR, memErrCopy, false)
|
||||
|
||||
// xn = weighted error (target for pitch search)
|
||||
// Residu(Ap1, error): error needs M history -> supplied as memErr before it.
|
||||
var eb [cM + cL_SUBFR]int16
|
||||
copy(eb[:cM], memErr[:cM])
|
||||
copy(eb[cM:], errSig[:cL_SUBFR])
|
||||
residu(ap1[:], eb[:], cM, cL_SUBFR, xn)
|
||||
|
||||
memW0Copy := make([]int16, cM)
|
||||
copy(memW0Copy, memW0[:cM])
|
||||
synFilt(ap2[:], xn, xn, cL_SUBFR, memW0Copy, false)
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
package amrnb
|
||||
|
||||
// Gain quantization (general modes), ported from opencore-amrnb qua_gain.cpp
|
||||
// (Qua_gain) and calc_en.cpp (calc_filt_energies). calcFiltEnergies forms the
|
||||
// five quadratic-form energy coefficients of the gain error from the target,
|
||||
// the adaptive codebook y1 and the filtered innovation y2; quaGain searches the
|
||||
// gain VQ table for the (pitch, code) gain pair minimizing that error, returning
|
||||
// the index and the dequantized gains — the exact encoder counterpart of
|
||||
// decGain. Bit-exact with the reference.
|
||||
|
||||
const (
|
||||
cVQ_SIZE_HIGHRATES = 128
|
||||
cVQ_SIZE_LOWRATES = 64
|
||||
)
|
||||
|
||||
// calcFiltEnergies computes the five energy coefficients (frac/exp) of the gain
|
||||
// MSE. gCoeff[0..3] are the <xn,y1>/<y1,y1> correlations from gPitch. For
|
||||
// MR795/MR475 it also returns the optimum unconstrained code gain. Mirrors
|
||||
// calc_filt_energies.
|
||||
func calcFiltEnergies(mode int, xn, xn2, y1, y2, gCoeff []int16) (fracCoeff, expCoeff [5]int16, codGainFrac, codGainExp int16) {
|
||||
fracCoeff[0] = gCoeff[0]
|
||||
expCoeff[0] = gCoeff[1]
|
||||
fracCoeff[1] = negate(gCoeff[2])
|
||||
expCoeff[1] = gCoeff[3] + 1
|
||||
|
||||
var s1, s2, s3 int32
|
||||
if mode != dMR795 && mode != dMR475 {
|
||||
s1, s2, s3 = 1, 1, 1
|
||||
}
|
||||
var scaledY2 [cL_SUBFR]int16
|
||||
for i := 0; i < cL_SUBFR; i++ {
|
||||
tmp := y2[i] >> 3
|
||||
scaledY2[i] = tmp
|
||||
s1 = L_mac(s1, tmp, tmp)
|
||||
s2 = L_mac(s2, xn[i], tmp)
|
||||
s3 = L_mac(s3, y1[i], tmp)
|
||||
}
|
||||
exp := norm_l(s1)
|
||||
fracCoeff[2] = int16(L_shl(s1, exp) >> 16)
|
||||
expCoeff[2] = -3 - exp
|
||||
exp = norm_l(s2)
|
||||
fracCoeff[3] = negate(int16(L_shl(s2, exp) >> 16))
|
||||
expCoeff[3] = 7 - exp
|
||||
exp = norm_l(s3)
|
||||
fracCoeff[4] = int16(L_shl(s3, exp) >> 16)
|
||||
expCoeff[4] = 7 - exp
|
||||
|
||||
if mode == dMR795 || mode == dMR475 {
|
||||
s1 = 0
|
||||
for i := 0; i < cL_SUBFR; i++ {
|
||||
s1 += int32(xn2[i]) * int32(scaledY2[i])
|
||||
}
|
||||
s1 <<= 1
|
||||
exp = norm_l(s1)
|
||||
frac := int16(L_shl(s1, exp) >> 16)
|
||||
exp = 6 - exp
|
||||
if frac <= 0 {
|
||||
codGainFrac = 0
|
||||
codGainExp = 0
|
||||
} else {
|
||||
codGainFrac = div_s(shr(frac, 1), fracCoeff[2])
|
||||
codGainExp = (exp - expCoeff[2]) - 14
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// quaGain searches the mode's gain VQ table for the (pitch, code) gain pair
|
||||
// minimizing the weighted gain MSE, returning the index and dequantized gains
|
||||
// plus the predictor-update energies. Mirrors Qua_gain.
|
||||
func quaGain(mode int, expGcode0, fracGcode0 int16, fracCoeff, expCoeff []int16, gpLimit int16) (index, gainPit, gainCod, quaEnerMR122, quaEner int16) {
|
||||
var tableGain []int16
|
||||
var tableLen int
|
||||
if mode == dMR102 || mode == dMR74 || mode == dMR67 {
|
||||
tableLen = cVQ_SIZE_HIGHRATES
|
||||
tableGain = table_gain_highrates
|
||||
} else {
|
||||
tableLen = cVQ_SIZE_LOWRATES
|
||||
tableGain = table_gain_lowrates
|
||||
}
|
||||
|
||||
gcode0 := int16(pow2(14, fracGcode0))
|
||||
expCode := expGcode0 - 11
|
||||
|
||||
var expMax [5]int16
|
||||
expMax[0] = expCoeff[0] - 13
|
||||
expMax[1] = expCoeff[1] - 14
|
||||
temp := shl(expCode, 1) + 15
|
||||
expMax[2] = add(expCoeff[2], temp)
|
||||
expMax[3] = add(expCoeff[3], expCode)
|
||||
expMax[4] = add(expCoeff[4], expCode+1)
|
||||
|
||||
eMax := expMax[0]
|
||||
for i := 1; i < 5; i++ {
|
||||
if expMax[i] > eMax {
|
||||
eMax = expMax[i]
|
||||
}
|
||||
}
|
||||
eMax++
|
||||
|
||||
var coeff, coeffLo [5]int16
|
||||
for i := 0; i < 5; i++ {
|
||||
j := eMax - expMax[i]
|
||||
coeff[i], coeffLo[i] = L_Extract(L_shr(int32(fracCoeff[i])<<16, j))
|
||||
}
|
||||
|
||||
distMin := int32(maxInt32)
|
||||
for i := 0; i < tableLen; i++ {
|
||||
p := i << 2
|
||||
gPitch := tableGain[p]
|
||||
gCode := tableGain[p+1]
|
||||
if gPitch <= gpLimit {
|
||||
gc := mult(gCode, gcode0)
|
||||
g2Pitch := mult(gPitch, gPitch)
|
||||
g2Code := mult(gc, gc)
|
||||
gPitCod := mult(gc, gPitch)
|
||||
L_tmp := mpy32_16(coeff[0], coeffLo[0], g2Pitch)
|
||||
L_tmp = L_add(L_tmp, mpy32_16(coeff[1], coeffLo[1], gPitch))
|
||||
L_tmp = L_add(L_tmp, mpy32_16(coeff[2], coeffLo[2], g2Code))
|
||||
L_tmp = L_add(L_tmp, mpy32_16(coeff[3], coeffLo[3], gc))
|
||||
L_tmp = L_add(L_tmp, mpy32_16(coeff[4], coeffLo[4], gPitCod))
|
||||
if L_tmp < distMin {
|
||||
distMin = L_tmp
|
||||
index = int16(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p := int(index) << 2
|
||||
gainPit = tableGain[p]
|
||||
gCode := tableGain[p+1]
|
||||
quaEnerMR122 = tableGain[p+2]
|
||||
quaEner = tableGain[p+3]
|
||||
|
||||
L_tmp := L_shr(L_mult(gCode, gcode0), 10-expGcode0)
|
||||
gainCod = int16(L_tmp >> 16)
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
package amrnb
|
||||
|
||||
// MR475 joint two-subframe gain quantization, ported from opencore-amrnb
|
||||
// qgain475.cpp (MR475_gain_quant, MR475_quant_store_results,
|
||||
// MR475_update_unq_pred) and the target-energy helper calc_en.cpp
|
||||
// (calc_target_energy). The 4.75 kbit/s mode quantizes the pitch and code gains
|
||||
// of two consecutive subframes jointly with a single 8-bit index into
|
||||
// table_gain_MR475, using an "unquantized" gain predictor (predUnq) to drive the
|
||||
// search and the real predictor (pred) for the reconstructed gains. Bit-exact
|
||||
// with the reference.
|
||||
|
||||
const (
|
||||
cMIN_QUA_ENER = -5443
|
||||
cMIN_QUA_ENER_MR122 = -32768
|
||||
cMAX_QUA_ENER = 3037
|
||||
cMAX_QUA_ENER_MR122 = 18284
|
||||
)
|
||||
|
||||
// calcTargetEnergy returns the energy of the LTP target xn as a normalized
|
||||
// (exponent, fraction) pair. Mirrors calc_target_energy.
|
||||
func calcTargetEnergy(xn []int16) (enExp, enFrac int16) {
|
||||
var s int32
|
||||
for i := 0; i < cL_SUBFR; i++ {
|
||||
s += int32(xn[i]) * int32(xn[i]) // 32-bit MAC, wraps like the reference
|
||||
}
|
||||
if s < 0 { // overflow wrapped negative
|
||||
s = maxInt32
|
||||
}
|
||||
exp := norm_l(s)
|
||||
enFrac = int16(L_shl(s, exp) >> 16)
|
||||
enExp = 16 - exp
|
||||
return
|
||||
}
|
||||
|
||||
// mr475StoreResults dequantizes one subframe's gains from a table entry p
|
||||
// (p[0]=gain_pit, p[1]=gain_code) given the predicted code gain gcode0, and
|
||||
// advances the predictor with the resulting quantized energy error. Mirrors
|
||||
// MR475_quant_store_results.
|
||||
func (pred *gcPredState) mr475StoreResults(p []int16, gcode0, expGcode0 int16) (gainPit, gainCod int16) {
|
||||
gainPit = p[0]
|
||||
gCode := p[1]
|
||||
|
||||
L := (int32(gCode) * int32(gcode0)) << 1
|
||||
L = L_shr(L, 10-expGcode0)
|
||||
gainCod = int16(L >> 16)
|
||||
|
||||
exp, frac := log2(int32(gCode))
|
||||
exp -= 12
|
||||
tmp := shr_r(frac, 5)
|
||||
quaEnerMR122 := (exp << 10) + tmp
|
||||
L2 := mpy32_16(exp, frac, 24660) << 13
|
||||
quaEner := int16((L2 + 0x00008000) >> 16)
|
||||
|
||||
pred.update(quaEnerMR122, quaEner)
|
||||
return
|
||||
}
|
||||
|
||||
// mr475UpdateUnqPred advances the "unquantized" predictor with the optimum
|
||||
// (unquantized) code gain of a subframe. Mirrors MR475_update_unq_pred.
|
||||
func (pred *gcPredState) mr475UpdateUnqPred(expGcode0, fracGcode0, codGainExp, codGainFrac int16) {
|
||||
var quaEner, quaEnerMR122 int16
|
||||
if codGainFrac <= 0 {
|
||||
quaEner = cMIN_QUA_ENER
|
||||
quaEnerMR122 = cMIN_QUA_ENER_MR122
|
||||
} else {
|
||||
fg := int16(pow2(14, fracGcode0))
|
||||
if codGainFrac >= fg {
|
||||
codGainFrac >>= 1
|
||||
codGainExp++
|
||||
}
|
||||
frac := div_s(codGainFrac, fg)
|
||||
tmp := codGainExp - expGcode0 - 1
|
||||
exp, fr := log2(int32(frac))
|
||||
exp += tmp
|
||||
quaEnerMR122 = shr_r(fr, 5) + (exp << 10)
|
||||
if quaEnerMR122 > cMAX_QUA_ENER_MR122 {
|
||||
quaEner = cMAX_QUA_ENER
|
||||
quaEnerMR122 = cMAX_QUA_ENER_MR122
|
||||
} else {
|
||||
L := L_shl(mpy32_16(exp, fr, 24660), 13)
|
||||
quaEner = round_(L)
|
||||
}
|
||||
}
|
||||
pred.update(quaEnerMR122, quaEner)
|
||||
}
|
||||
|
||||
// mr475GainQuant runs the joint pitch+code gain VQ for a subframe pair: it
|
||||
// searches table_gain_MR475 for the entry minimizing the combined weighted
|
||||
// error of both subframes (respecting the pitch-gain limit), stores the
|
||||
// reconstructed gains for both subframes, and returns the table index. The sf0
|
||||
// energy terms were stashed in st by the even-subframe pass; the sf1 terms are
|
||||
// passed in. Mirrors MR475_gain_quant.
|
||||
func (st *coderState) mr475GainQuant(sf1Code []int16, sf1ExpGcode0, sf1FracGcode0 int16,
|
||||
sf1ExpCoeff, sf1FracCoeff []int16, sf1ExpTargetEn, sf1FracTargetEn, gpLimit int16) (index, sf0GainPit, sf0GainCod, sf1GainPit, sf1GainCod int16) {
|
||||
|
||||
sf0Gcode0 := int16(pow2(14, st.sf0FracGcode0))
|
||||
sf1Gcode0 := int16(pow2(14, sf1FracGcode0))
|
||||
|
||||
// per-coefficient exponents (0..4: sf0, 5..9: sf1)
|
||||
var expMax [10]int16
|
||||
exp := st.sf0ExpGcode0 - 11
|
||||
expMax[0] = st.sf0ExpCoeff[0] - 13
|
||||
expMax[1] = st.sf0ExpCoeff[1] - 14
|
||||
expMax[2] = st.sf0ExpCoeff[2] + (15 + (exp << 1))
|
||||
expMax[3] = st.sf0ExpCoeff[3] + exp
|
||||
expMax[4] = st.sf0ExpCoeff[4] + (1 + exp)
|
||||
exp = sf1ExpGcode0 - 11
|
||||
expMax[5] = sf1ExpCoeff[0] - 13
|
||||
expMax[6] = sf1ExpCoeff[1] - 14
|
||||
expMax[7] = sf1ExpCoeff[2] + (15 + (exp << 1))
|
||||
expMax[8] = sf1ExpCoeff[3] + exp
|
||||
expMax[9] = sf1ExpCoeff[4] + (1 + exp)
|
||||
|
||||
// scale the two target energies to a common exponent, then nudge the sf0
|
||||
// coefficient exponents so the two subframes' errors are comparable.
|
||||
sf0FracTargetEn := st.sf0FracTargetEn
|
||||
if e := st.sf0ExpTargetEn - sf1ExpTargetEn; e > 0 {
|
||||
sf1FracTargetEn >>= uint(e)
|
||||
} else {
|
||||
sf0FracTargetEn >>= uint(-e)
|
||||
}
|
||||
adj := int16(0)
|
||||
if tmp := shr_r(sf1FracTargetEn, 1); tmp > sf0FracTargetEn {
|
||||
adj = 1
|
||||
} else if (sf0FracTargetEn+3)>>2 > sf1FracTargetEn {
|
||||
adj = -1
|
||||
}
|
||||
for i := 0; i < 5; i++ {
|
||||
expMax[i] += adj
|
||||
}
|
||||
|
||||
// common exponent for all 10 coefficients
|
||||
mx := expMax[0]
|
||||
for i := 9; i > 0; i-- {
|
||||
if expMax[i] > mx {
|
||||
mx = expMax[i]
|
||||
}
|
||||
}
|
||||
mx++ // avoid overflow
|
||||
|
||||
var coeff, coeffLo [10]int16
|
||||
for i := 0; i < 10; i++ {
|
||||
var fc int16
|
||||
if i < 5 {
|
||||
fc = st.sf0FracCoeff[i]
|
||||
} else {
|
||||
fc = sf1FracCoeff[i-5]
|
||||
}
|
||||
L := L_shr(int32(fc)<<16, mx-expMax[i])
|
||||
coeff[i] = int16(L >> 16)
|
||||
coeffLo[i] = int16((L >> 1) - ((L >> 16) << 15))
|
||||
}
|
||||
|
||||
// exhaustive search over the 256-entry joint codebook
|
||||
distMin := int32(maxInt32)
|
||||
index = 0
|
||||
for i := 0; i < cMR475_VQ_SIZE; i++ {
|
||||
b := i * 4
|
||||
gPitch := table_gain_MR475[b]
|
||||
gCode := int16((int32(table_gain_MR475[b+1]) * int32(sf0Gcode0)) >> 15)
|
||||
g2Pitch := int16((int32(gPitch) * int32(gPitch)) >> 15)
|
||||
g2Code := int16((int32(gCode) * int32(gCode)) >> 15)
|
||||
gPitCod := int16((int32(gCode) * int32(gPitch)) >> 15)
|
||||
L := mpy32_16(coeff[0], coeffLo[0], g2Pitch) +
|
||||
mpy32_16(coeff[1], coeffLo[1], gPitch) +
|
||||
mpy32_16(coeff[2], coeffLo[2], g2Code) +
|
||||
mpy32_16(coeff[3], coeffLo[3], gCode) +
|
||||
mpy32_16(coeff[4], coeffLo[4], gPitCod)
|
||||
|
||||
tmp := gPitch - gpLimit
|
||||
gPitch1 := table_gain_MR475[b+2]
|
||||
if tmp <= 0 && gPitch1 <= gpLimit {
|
||||
gCode1 := int16((int32(table_gain_MR475[b+3]) * int32(sf1Gcode0)) >> 15)
|
||||
g2Pitch = int16((int32(gPitch1) * int32(gPitch1)) >> 15)
|
||||
g2Code = int16((int32(gCode1) * int32(gCode1)) >> 15)
|
||||
gPitCod = int16((int32(gCode1) * int32(gPitch1)) >> 15)
|
||||
L += mpy32_16(coeff[5], coeffLo[5], g2Pitch) +
|
||||
mpy32_16(coeff[6], coeffLo[6], gPitch1) +
|
||||
mpy32_16(coeff[7], coeffLo[7], g2Code) +
|
||||
mpy32_16(coeff[8], coeffLo[8], gCode1) +
|
||||
mpy32_16(coeff[9], coeffLo[9], gPitCod)
|
||||
if L < distMin {
|
||||
distMin = L
|
||||
index = int16(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// reconstruct sf0 gains (updates the real predictor), re-predict, then sf1
|
||||
base := int(index) << 2
|
||||
sf0GainPit, sf0GainCod = st.pred.mr475StoreResults(table_gain_MR475[base:], sf0Gcode0, st.sf0ExpGcode0)
|
||||
gp := st.pred.gcPred(dMR475, sf1Code)
|
||||
sf1Gcode0 = int16(pow2(14, gp.fracGcode0))
|
||||
sf1GainPit, sf1GainCod = st.pred.mr475StoreResults(table_gain_MR475[base+2:], sf1Gcode0, gp.expGcode0)
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,314 @@
|
||||
package amrnb
|
||||
|
||||
// MR795 gain quantization, ported from opencore-amrnb qgain795.cpp
|
||||
// (MR795_gain_quant, MR795_gain_code_quant3, MR795_gain_code_quant_mod), the
|
||||
// gain adaptor g_adapt.cpp (gain_adapt) + gmed_n.cpp (gmed_n), and the unfiltered
|
||||
// energies calc_en.cpp (calc_unfilt_energies). MR795 jointly searches the three
|
||||
// nearest pitch-gain candidates against the code-gain VQ, then — when the LTP is
|
||||
// strong enough (alpha>0) — re-quantizes the code gain with a perceptually
|
||||
// adapted criterion. It emits two indices per subframe. Bit-exact with the
|
||||
// reference.
|
||||
|
||||
const (
|
||||
cLTP_GAIN_THR1 = 2721 // Q13
|
||||
cLTP_GAIN_THR2 = 5443 // Q13
|
||||
cLTPG_MEM_SIZE = 5
|
||||
)
|
||||
|
||||
// gmedN returns the median of the first n values of ind, matching the
|
||||
// index-based tie-breaking of the reference. Mirrors gmed_n.
|
||||
func gmedN(ind []int16, n int) int16 {
|
||||
tmp2 := make([]int16, n)
|
||||
copy(tmp2, ind[:n])
|
||||
tmp := make([]int16, n)
|
||||
ix := 0
|
||||
for i := 0; i < n; i++ {
|
||||
max := int16(-32767)
|
||||
for j := 0; j < n; j++ {
|
||||
if tmp2[j] >= max {
|
||||
max = tmp2[j]
|
||||
ix = j
|
||||
}
|
||||
}
|
||||
tmp2[ix] = -32768
|
||||
tmp[i] = int16(ix)
|
||||
}
|
||||
return ind[tmp[n>>1]]
|
||||
}
|
||||
|
||||
// gainAdaptState is the gain adaptor's persistent state. Mirrors GainAdaptState.
|
||||
type gainAdaptState struct {
|
||||
onset int16
|
||||
prevAlpha int16
|
||||
prevGc int16
|
||||
ltpgMem [cLTPG_MEM_SIZE]int16
|
||||
}
|
||||
|
||||
// gainAdapt computes the gain adaptation factor alpha (Q15) from the LTP coding
|
||||
// gain ltpg and the code gain, updating the onset/history state. Mirrors
|
||||
// gain_adapt.
|
||||
func (st *gainAdaptState) gainAdapt(ltpg, gainCod int16) int16 {
|
||||
var adapt int16
|
||||
switch {
|
||||
case ltpg <= cLTP_GAIN_THR1:
|
||||
adapt = 0
|
||||
case ltpg <= cLTP_GAIN_THR2:
|
||||
adapt = 1
|
||||
default:
|
||||
adapt = 2
|
||||
}
|
||||
|
||||
if tmp := shr_r(gainCod, 1); tmp > st.prevGc && gainCod > 200 {
|
||||
st.onset = 8
|
||||
} else if st.onset != 0 {
|
||||
st.onset--
|
||||
}
|
||||
if st.onset != 0 && adapt < 2 {
|
||||
adapt++
|
||||
}
|
||||
|
||||
st.ltpgMem[0] = ltpg
|
||||
filt := gmedN(st.ltpgMem[:], 5)
|
||||
var result int16
|
||||
if adapt == 0 {
|
||||
switch {
|
||||
case filt > 5443:
|
||||
result = 0
|
||||
case filt < 0:
|
||||
result = 16384
|
||||
default:
|
||||
filt = shl(filt, 2)
|
||||
result = 16384 - mult(24660, filt)
|
||||
}
|
||||
}
|
||||
if st.prevAlpha == 0 {
|
||||
result = shr(result, 1)
|
||||
}
|
||||
|
||||
st.prevAlpha = result
|
||||
st.prevGc = gainCod
|
||||
for i := cLTPG_MEM_SIZE - 1; i > 0; i-- {
|
||||
st.ltpgMem[i] = st.ltpgMem[i-1]
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// calcUnfiltEnergies computes the unfiltered residual/excitation/cross/LTP-error
|
||||
// energies (as 4 normalized exp/frac pairs) and the LTP coding gain ltpg.
|
||||
// Mirrors calc_unfilt_energies.
|
||||
func calcUnfiltEnergies(res, exc, code []int16, gainPit int16, Lsubfr int) (fracEn, expEn [4]int16, ltpg int16) {
|
||||
var s1, s2, s3, s4 int32
|
||||
for i := 0; i < Lsubfr; i++ {
|
||||
tmp1 := res[i]
|
||||
tmp2 := exc[i]
|
||||
s1 += int32(tmp1) * int32(tmp1) // wrapping MAC, like the reference
|
||||
s2 += int32(tmp2) * int32(tmp2)
|
||||
s3 += int32(tmp2) * int32(code[i])
|
||||
Ltemp := L_shl(L_mult(tmp2, gainPit), 1)
|
||||
d := sub(tmp1, round_(Ltemp))
|
||||
s4 = L_mac(s4, d, d)
|
||||
}
|
||||
s1 <<= 1
|
||||
s2 <<= 1
|
||||
s3 <<= 1
|
||||
|
||||
if s1 < 0 { // overflow (sign bit set)
|
||||
s1 = maxInt32
|
||||
}
|
||||
if s1 < 400 {
|
||||
fracEn[0] = 0
|
||||
expEn[0] = -15
|
||||
} else {
|
||||
exp := norm_l(s1)
|
||||
fracEn[0] = int16(L_shl(s1, exp) >> 16)
|
||||
expEn[0] = 15 - exp
|
||||
}
|
||||
|
||||
if s2 < 0 {
|
||||
s2 = maxInt32
|
||||
}
|
||||
exp := norm_l(s2)
|
||||
fracEn[1] = int16(L_shl(s2, exp) >> 16)
|
||||
expEn[1] = 15 - exp
|
||||
|
||||
exp = norm_l(s3)
|
||||
fracEn[2] = int16(L_shl(s3, exp) >> 16)
|
||||
expEn[2] = 2 - exp
|
||||
|
||||
exp = norm_l(s4)
|
||||
ltpResEn := int16(L_shl(s4, exp) >> 16)
|
||||
expS4 := 15 - exp
|
||||
fracEn[3] = ltpResEn
|
||||
expEn[3] = expS4
|
||||
|
||||
if ltpResEn > 0 && fracEn[0] != 0 {
|
||||
predGain := div_s(shr(fracEn[0], 1), ltpResEn)
|
||||
e := sub(expS4, expEn[0])
|
||||
Ltemp := L_shr(int32(predGain)<<16, e+3)
|
||||
ltpgExp, ltpgFrac := log2(Ltemp)
|
||||
Ltemp = L_Comp(ltpgExp-27, ltpgFrac)
|
||||
ltpg = round_(L_shl(Ltemp, 13)) // Q13
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// mr795GainCodeQuant3 jointly searches the three pitch-gain candidates against
|
||||
// the code-gain VQ for the minimum weighted error, returning the selected pitch
|
||||
// and code gains, their indices, and the predictor-update energies. Mirrors
|
||||
// MR795_gain_code_quant3.
|
||||
func mr795GainCodeQuant3(expGcode0, gcode0 int16, gpCand, gpCind, fracCoeff, expCoeff []int16) (gainPit, gainPitInd, gainCod, gainCodInd, quaEnerMR122, quaEner int16) {
|
||||
var coeff, coeffLo, expMax [5]int16
|
||||
expCode := expGcode0 - 10
|
||||
expMax[0] = expCoeff[0] - 13
|
||||
expMax[1] = expCoeff[1] - 14
|
||||
expMax[2] = expCoeff[2] + shl(expCode, 1) + 15
|
||||
expMax[3] = expCoeff[3] + expCode
|
||||
expMax[4] = expCoeff[4] + (expCode + 1)
|
||||
|
||||
eMax := expMax[0]
|
||||
for i := 1; i < 5; i++ {
|
||||
if expMax[i] > eMax {
|
||||
eMax = expMax[i]
|
||||
}
|
||||
}
|
||||
eMax = add(eMax, 1)
|
||||
for i := 0; i < 5; i++ {
|
||||
coeff[i], coeffLo[i] = L_Extract(L_shr(int32(fracCoeff[i])<<16, eMax-expMax[i]))
|
||||
}
|
||||
|
||||
distMin := int32(maxInt32)
|
||||
var codInd, pitInd int16
|
||||
for j := 0; j < 3; j++ {
|
||||
gPitch := gpCand[j]
|
||||
g2Pitch := mult(gPitch, gPitch)
|
||||
Ltmp0 := mpy32_16(coeff[0], coeffLo[0], g2Pitch)
|
||||
Ltmp0 = L_add(Ltmp0, mpy32_16(coeff[1], coeffLo[1], gPitch))
|
||||
for i := 0; i < cNB_QUA_CODE; i++ {
|
||||
gCode := mult(qua_gain_code[i*3], gcode0)
|
||||
g2h, g2l := L_Extract(L_mult(gCode, gCode))
|
||||
gpch, gpcl := L_Extract(L_mult(gCode, gPitch))
|
||||
Ltmp := L_add(Ltmp0, mpy_32(coeff[2], coeffLo[2], g2h, g2l))
|
||||
Ltmp = L_add(Ltmp, mpy32_16(coeff[3], coeffLo[3], gCode))
|
||||
Ltmp = L_add(Ltmp, mpy_32(coeff[4], coeffLo[4], gpch, gpcl))
|
||||
if Ltmp < distMin {
|
||||
distMin = Ltmp
|
||||
codInd = int16(i)
|
||||
pitInd = int16(j)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
base := int(codInd) * 3
|
||||
gCode := qua_gain_code[base]
|
||||
quaEnerMR122 = qua_gain_code[base+1]
|
||||
quaEner = qua_gain_code[base+2]
|
||||
gainCod = int16(L_shr(L_mult(gCode, gcode0), 9-expGcode0) >> 16)
|
||||
gainCodInd = codInd
|
||||
gainPit = gpCand[pitInd]
|
||||
gainPitInd = gpCind[pitInd]
|
||||
return
|
||||
}
|
||||
|
||||
// mr795GainCodeQuantMod re-quantizes the code gain with the gain-adapted
|
||||
// criterion once the LTP is strong (alpha>0), returning the new index and
|
||||
// predictor energies and updating gainCod in place. Mirrors
|
||||
// MR795_gain_code_quant_mod.
|
||||
func mr795GainCodeQuantMod(gainPit, expGcode0, gcode0 int16, fracEn, expEn []int16, alpha, gainCodUnq int16, gainCod *int16) (index, quaEnerMR122, quaEner int16) {
|
||||
var coeff, coeffLo, expCoeff [5]int16
|
||||
gainCode := shl(*gainCod, 10-expGcode0) // Q1 -> Q11(-ec0)
|
||||
g2Pitch := mult(gainPit, gainPit)
|
||||
oneAlpha := add(32767-alpha, 1) // 32768 - alpha
|
||||
|
||||
Lt1 := L_shl(L_mult(alpha, fracEn[1]), 1)
|
||||
Lt1 = L_mult(int16(Lt1>>16), g2Pitch)
|
||||
expCoeff[1] = expEn[1] - 15
|
||||
|
||||
coeff[2] = mult(int16(L_shl(L_mult(alpha, fracEn[2]), 1)>>16), gainPit)
|
||||
expCoeff[2] = add(expEn[2], expGcode0-10)
|
||||
|
||||
coeff[3] = int16(L_shl(L_mult(alpha, fracEn[3]), 1) >> 16)
|
||||
expCoeff[3] = add(expEn[3], shl(expGcode0, 1)-7)
|
||||
|
||||
coeff[4] = mult(oneAlpha, fracEn[3])
|
||||
expCoeff[4] = add(expCoeff[3], 1)
|
||||
|
||||
Lt0, sqExp := sqrtLExp(L_mult(alpha, fracEn[0]))
|
||||
sqExp += 47
|
||||
expCoeff[0] = expEn[0] - sqExp
|
||||
|
||||
eMax := expCoeff[0] + 31
|
||||
for i := 1; i <= 4; i++ {
|
||||
if expCoeff[i] > eMax {
|
||||
eMax = expCoeff[i]
|
||||
}
|
||||
}
|
||||
Lt1 = L_shr(Lt1, eMax-expCoeff[1])
|
||||
for i := 2; i <= 4; i++ {
|
||||
coeff[i], coeffLo[i] = L_Extract(L_shr(int32(coeff[i])<<16, eMax-expCoeff[i]))
|
||||
}
|
||||
newExp := eMax - 31
|
||||
tmp := newExp - expCoeff[0]
|
||||
Lt0 = L_shr(Lt0, shr(tmp, 1))
|
||||
if tmp&0x1 != 0 {
|
||||
coeff[0], coeffLo[0] = L_Extract(Lt0)
|
||||
Lt0 = mpy32_16(coeff[0], coeffLo[0], 23170) // 1/sqrt(2) Q15
|
||||
}
|
||||
|
||||
distMin := int32(maxInt32)
|
||||
index = 0
|
||||
for i := 0; i < cNB_QUA_CODE; i++ {
|
||||
gCode := mult(qua_gain_code[i*3], gcode0)
|
||||
if gCode >= gainCode {
|
||||
break
|
||||
}
|
||||
g2h, g2l := L_Extract(L_mult(gCode, gCode))
|
||||
d := sub(gCode, gainCodUnq)
|
||||
d2h, d2l := L_Extract(L_mult(d, d))
|
||||
Ltmp := L_add(Lt1, mpy32_16(coeff[2], coeffLo[2], gCode))
|
||||
Ltmp = L_add(Ltmp, mpy_32(coeff[3], coeffLo[3], g2h, g2l))
|
||||
sq, e := sqrtLExp(Ltmp)
|
||||
sq = L_shr(sq, shr(e, 1))
|
||||
t := round_(L_sub(sq, Lt0))
|
||||
Ltmp = L_mult(t, t)
|
||||
Ltmp = L_add(Ltmp, mpy_32(coeff[4], coeffLo[4], d2h, d2l))
|
||||
if Ltmp < distMin {
|
||||
distMin = Ltmp
|
||||
index = int16(i)
|
||||
}
|
||||
}
|
||||
|
||||
base := int(index) * 3
|
||||
gCode := qua_gain_code[base]
|
||||
quaEnerMR122 = qua_gain_code[base+1]
|
||||
quaEner = qua_gain_code[base+2]
|
||||
*gainCod = int16(L_shr(L_mult(gCode, gcode0), 9-expGcode0) >> 16)
|
||||
return
|
||||
}
|
||||
|
||||
// mr795GainQuant orchestrates the MR795 gain quantization for one subframe,
|
||||
// updating *gainPit and returning the quantized gains, predictor energies and
|
||||
// the two analysis indices. Mirrors MR795_gain_quant.
|
||||
func (st *coderState) mr795GainQuant(res, exc, code, fracCoeff, expCoeff []int16,
|
||||
expCodeEn, fracCodeEn, expGcode0, fracGcode0, codGainFrac, codGainExp, gpLimit int16,
|
||||
gainPit *int16) (gainCod, quaEnerMR122, quaEner, gainPitIndex, gainCodIndex int16) {
|
||||
|
||||
var gpCand, gpCind [3]int16
|
||||
qGainPitch(dMR795, gpLimit, gainPit, gpCand[:], gpCind[:])
|
||||
gcode0 := int16(pow2(14, fracGcode0))
|
||||
|
||||
gp, gpInd, gc, gcInd, qe122, qe := mr795GainCodeQuant3(expGcode0, gcode0, gpCand[:], gpCind[:], fracCoeff, expCoeff)
|
||||
*gainPit = gp
|
||||
gainPitIndex, gainCod = gpInd, gc
|
||||
gainCodIndex, quaEnerMR122, quaEner = gcInd, qe122, qe
|
||||
|
||||
fracEn, expEn, ltpg := calcUnfiltEnergies(res, exc, code, *gainPit, cL_SUBFR)
|
||||
alpha := st.adapt.gainAdapt(ltpg, gainCod)
|
||||
if fracEn[0] != 0 && alpha > 0 {
|
||||
fracEn[3] = fracCodeEn
|
||||
expEn[3] = expCodeEn
|
||||
gainCodUnq := shl(codGainFrac, sub(codGainExp, expGcode0)+10)
|
||||
gainCodIndex, quaEnerMR122, quaEner = mr795GainCodeQuantMod(*gainPit, expGcode0, gcode0,
|
||||
fracEn[:], expEn[:], alpha, gainCodUnq, &gainCod)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package amrnb
|
||||
|
||||
// Separate pitch/code gain quantizers (MR122; pitch also used by MR795), ported
|
||||
// from opencore-amrnb q_gain_p.cpp (q_gain_pitch) and q_gain_c.cpp
|
||||
// (q_gain_code). qGainPitch picks the nearest quantized pitch gain; qGainCode
|
||||
// picks the code-gain index minimizing the error to the predicted gain. The
|
||||
// exact encoder counterparts of dGainPitch / dGainCode. Bit-exact with the
|
||||
// reference.
|
||||
|
||||
const (
|
||||
cNB_QUA_PITCH = 16
|
||||
cNB_QUA_CODE = 32
|
||||
)
|
||||
|
||||
// qGainPitch quantizes the pitch gain (in place) to the nearest table entry
|
||||
// within gpLimit, returning the index. For MR795 it also fills three candidate
|
||||
// gains/indices. Mirrors q_gain_pitch.
|
||||
func qGainPitch(mode int, gpLimit int16, gain *int16, gainCand, gainCind []int16) int16 {
|
||||
errMin := abs_s(sub(*gain, qua_gain_pitch[0]))
|
||||
index := int16(0)
|
||||
for i := int16(1); i < cNB_QUA_PITCH; i++ {
|
||||
if qua_gain_pitch[i] <= gpLimit {
|
||||
err := abs_s(sub(*gain, qua_gain_pitch[i]))
|
||||
if err < errMin {
|
||||
errMin = err
|
||||
index = i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if mode == dMR795 {
|
||||
var ii int16
|
||||
switch {
|
||||
case index == 0:
|
||||
ii = index
|
||||
case index == cNB_QUA_PITCH-1 || qua_gain_pitch[index+1] > gpLimit:
|
||||
ii = index - 2
|
||||
default:
|
||||
ii = index - 1
|
||||
}
|
||||
for i := 0; i < 3; i++ {
|
||||
gainCind[i] = ii
|
||||
gainCand[i] = qua_gain_pitch[ii]
|
||||
ii++
|
||||
}
|
||||
*gain = qua_gain_pitch[index]
|
||||
} else if mode == dMR122 {
|
||||
*gain = qua_gain_pitch[index] &^ 3
|
||||
} else {
|
||||
*gain = qua_gain_pitch[index]
|
||||
}
|
||||
return index
|
||||
}
|
||||
|
||||
// qGainCode quantizes the fixed-codebook gain (in place) against the predicted
|
||||
// gain, returning the index and the predictor-update energies. Mirrors
|
||||
// q_gain_code.
|
||||
func qGainCode(mode int, expGcode0, fracGcode0 int16, gain *int16) (index, quaEnerMR122, quaEner int16) {
|
||||
var gQ0 int16
|
||||
if mode == dMR122 {
|
||||
gQ0 = *gain >> 1 // Q1 -> Q0
|
||||
} else {
|
||||
gQ0 = *gain
|
||||
}
|
||||
|
||||
gcode0 := int16(pow2(expGcode0, fracGcode0))
|
||||
if mode == dMR122 {
|
||||
gcode0 = shl(gcode0, 4)
|
||||
} else {
|
||||
gcode0 = shl(gcode0, 5)
|
||||
}
|
||||
|
||||
errMin := gQ0 - int16((int32(gcode0)*int32(qua_gain_code[0]))>>15)
|
||||
if errMin < 0 {
|
||||
errMin = -errMin
|
||||
}
|
||||
index = 0
|
||||
for i := int16(1); i < cNB_QUA_CODE; i++ {
|
||||
err := gQ0 - int16((int32(gcode0)*int32(qua_gain_code[i*3]))>>15)
|
||||
if err < 0 {
|
||||
err = -err
|
||||
}
|
||||
if err < errMin {
|
||||
errMin = err
|
||||
index = i
|
||||
}
|
||||
}
|
||||
|
||||
p := int(index) * 3
|
||||
temp := int16((int32(gcode0) * int32(qua_gain_code[p])) >> 15)
|
||||
if mode == dMR122 {
|
||||
*gain = temp << 1
|
||||
} else {
|
||||
*gain = temp
|
||||
}
|
||||
quaEnerMR122 = qua_gain_code[p+1]
|
||||
quaEner = qua_gain_code[p+2]
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,321 @@
|
||||
package amrnb
|
||||
|
||||
// Encoder LSF quantization, ported from opencore-amrnb q_plsf_3.cpp (Q_plsf_3,
|
||||
// Vq_subvec3, Vq_subvec4) and lsfwt.cpp (Lsf_wt). Q_plsf_3 is the split-VQ LSF
|
||||
// quantizer for all modes except 12.2 kbit/s: it converts the analysis LSPs to
|
||||
// weighted LSFs, removes the MA prediction, and searches the LSF codebooks for
|
||||
// the indices the bitstream carries. It is the exact encoder counterpart of the
|
||||
// decoder's dPlsf3 — feeding its indices back through dPlsf3 reproduces the same
|
||||
// quantized LSPs. Bit-exact with the reference.
|
||||
|
||||
// qPlsfState holds the encoder LSF MA-predictor memory. Mirrors Q_plsfState.
|
||||
type qPlsfState struct {
|
||||
pastRQ [cM]int16
|
||||
}
|
||||
|
||||
func (st *qPlsfState) reset() {
|
||||
for i := range st.pastRQ {
|
||||
st.pastRQ[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
// lsfWt computes the LSF weighting factors (squared, Q13<<3). Mirrors Lsf_wt.
|
||||
func lsfWt(lsf, wf []int16) {
|
||||
wf[0] = lsf[1]
|
||||
for i := 1; i <= 8; i++ {
|
||||
wf[i] = lsf[i+1] - lsf[i-1]
|
||||
}
|
||||
wf[9] = 16384 - lsf[8] // reference's pointer ends at lsf[M-2] here, not lsf[M-1]
|
||||
|
||||
for i := 0; i < cM; i++ {
|
||||
wgt := wf[i]
|
||||
temp := wgt - 1843
|
||||
if temp > 0 {
|
||||
temp = int16((int32(temp) * 6242) >> 15)
|
||||
wgt = 1843 - temp
|
||||
} else {
|
||||
temp = int16((int32(wgt) * 28160) >> 15)
|
||||
wgt = 3427 - temp
|
||||
}
|
||||
wf[i] = shl(wgt, 3)
|
||||
}
|
||||
}
|
||||
|
||||
// vqSubvec3 finds the weighted nearest codebook entry for a 3-element LSF
|
||||
// residual, writing the chosen entry back into lsfR1[0:3]. useHalf searches only
|
||||
// every second codebook entry. Mirrors Vq_subvec3.
|
||||
func vqSubvec3(lsfR1, dico, wf1 []int16, dicoSize int, useHalf bool) int16 {
|
||||
distMin := int32(maxInt32)
|
||||
index := int16(0)
|
||||
stride := 0
|
||||
if useHalf {
|
||||
stride = 3
|
||||
}
|
||||
l0, l1, l2 := lsfR1[0], lsfR1[1], lsfR1[2]
|
||||
w0, w1, w2 := wf1[0], wf1[1], wf1[2]
|
||||
|
||||
di := 0
|
||||
advance := 3 + stride
|
||||
for i := 0; i < dicoSize; i++ {
|
||||
row := dico[di : di+3] // hoist the per-dim bounds checks
|
||||
di += advance
|
||||
t := int16((int32(w0) * int32(l0-row[0])) >> 15)
|
||||
dist := int32(t) * int32(t)
|
||||
t = int16((int32(w1) * int32(l1-row[1])) >> 15)
|
||||
dist += int32(t) * int32(t)
|
||||
t = int16((int32(w2) * int32(l2-row[2])) >> 15)
|
||||
dist += int32(t) * int32(t)
|
||||
|
||||
if dist < distMin {
|
||||
distMin = dist
|
||||
index = int16(i)
|
||||
}
|
||||
}
|
||||
|
||||
pd := 3 * int(index)
|
||||
if useHalf {
|
||||
pd += 3 * int(index)
|
||||
}
|
||||
lsfR1[0] = dico[pd]
|
||||
lsfR1[1] = dico[pd+1]
|
||||
lsfR1[2] = dico[pd+2]
|
||||
return index
|
||||
}
|
||||
|
||||
// vqSubvec4 finds the weighted nearest codebook entry for a 4-element LSF
|
||||
// residual, writing the chosen entry back into lsfR1[0:4]. Mirrors Vq_subvec4.
|
||||
func vqSubvec4(lsfR1, dico, wf1 []int16, dicoSize int) int16 {
|
||||
distMin := int32(maxInt32)
|
||||
index := int16(0)
|
||||
l0, l1, l2, l3 := lsfR1[0], lsfR1[1], lsfR1[2], lsfR1[3]
|
||||
w0, w1, w2, w3 := wf1[0], wf1[1], wf1[2], wf1[3]
|
||||
|
||||
di := 0
|
||||
for i := 0; i < dicoSize; i++ {
|
||||
row := dico[di : di+4] // hoist the per-dim bounds checks
|
||||
di += 4
|
||||
t := int16((int32(w0) * int32(l0-row[0])) >> 15)
|
||||
dist := int32(t) * int32(t)
|
||||
t = int16((int32(w1) * int32(l1-row[1])) >> 15)
|
||||
dist += int32(t) * int32(t)
|
||||
t = int16((int32(w2) * int32(l2-row[2])) >> 15)
|
||||
dist += int32(t) * int32(t)
|
||||
t = int16((int32(w3) * int32(l3-row[3])) >> 15)
|
||||
dist += int32(t) * int32(t)
|
||||
|
||||
if dist < distMin {
|
||||
distMin = dist
|
||||
index = int16(i)
|
||||
}
|
||||
}
|
||||
|
||||
pd := int(index) << 2
|
||||
lsfR1[0] = dico[pd]
|
||||
lsfR1[1] = dico[pd+1]
|
||||
lsfR1[2] = dico[pd+2]
|
||||
lsfR1[3] = dico[pd+3]
|
||||
return index
|
||||
}
|
||||
|
||||
// qPlsf3 quantizes the analysis LSPs for the given mode into three split-VQ
|
||||
// indices and the quantized LSP vector, updating the predictor. Mirrors
|
||||
// Q_plsf_3 (non-DTX path). Returns the three indices.
|
||||
func (st *qPlsfState) qPlsf3(mode int, lsp1 []int16, lsp1q []int16) [3]int16 {
|
||||
var lsf1, wf1, lsfP, lsfR1, lsf1q [cM]int16
|
||||
|
||||
lspLsf(lsp1, lsf1[:], cM)
|
||||
lsfWt(lsf1[:], wf1[:])
|
||||
|
||||
for i := 0; i < cM; i++ {
|
||||
temp := int16((int32(st.pastRQ[i]) * int32(pred_fac_3[i])) >> 15)
|
||||
lsfP[i] = mean_lsf_3[i] + temp
|
||||
lsfR1[i] = lsf1[i] - lsfP[i]
|
||||
}
|
||||
|
||||
var indice [3]int16
|
||||
switch {
|
||||
case mode == dMR475 || mode == dMR515:
|
||||
indice[0] = vqSubvec3(lsfR1[0:], dico1_lsf_3, wf1[0:], cDICO1_SIZE, false)
|
||||
indice[1] = vqSubvec3(lsfR1[3:], dico2_lsf_3, wf1[3:], cDICO2_SIZE/2, true)
|
||||
indice[2] = vqSubvec4(lsfR1[6:], mr515_3_lsf, wf1[6:], cMR515_3_SIZE)
|
||||
case mode == dMR795:
|
||||
indice[0] = vqSubvec3(lsfR1[0:], mr795_1_lsf, wf1[0:], cMR795_1_SIZE, false)
|
||||
indice[1] = vqSubvec3(lsfR1[3:], dico2_lsf_3, wf1[3:], cDICO2_SIZE, false)
|
||||
indice[2] = vqSubvec4(lsfR1[6:], dico3_lsf_3, wf1[6:], cDICO3_SIZE)
|
||||
default: // MR59, MR67, MR74, MR102
|
||||
indice[0] = vqSubvec3(lsfR1[0:], dico1_lsf_3, wf1[0:], cDICO1_SIZE, false)
|
||||
indice[1] = vqSubvec3(lsfR1[3:], dico2_lsf_3, wf1[3:], cDICO2_SIZE, false)
|
||||
indice[2] = vqSubvec4(lsfR1[6:], dico3_lsf_3, wf1[6:], cDICO3_SIZE)
|
||||
}
|
||||
|
||||
for i := 0; i < cM; i++ {
|
||||
lsf1q[i] = add(lsfR1[i], lsfP[i])
|
||||
st.pastRQ[i] = lsfR1[i]
|
||||
}
|
||||
|
||||
reorderLsf(lsf1q[:], cLSF_GAP, cM)
|
||||
lsfLsp(lsf1q[:], lsp1q, cM)
|
||||
return indice
|
||||
}
|
||||
|
||||
// LSF-5 split-VQ codebook sizes (q_plsf_5_tbl.cpp).
|
||||
const (
|
||||
cDICO1_5_SIZE = 128
|
||||
cDICO2_5_SIZE = 256
|
||||
cDICO3_5_SIZE = 256
|
||||
cDICO4_5_SIZE = 256
|
||||
cDICO5_5_SIZE = 64
|
||||
)
|
||||
|
||||
// vqSubvec finds the weighted nearest 4-element codebook entry (two LSFs from
|
||||
// each of the two LSF vectors), writing it back into lsfR1[0:2]/lsfR2[0:2].
|
||||
// Mirrors Vq_subvec.
|
||||
func vqSubvec(lsfR1, lsfR2, dico, wf1, wf2 []int16, dicoSize int) int16 {
|
||||
distMin := int32(maxInt32)
|
||||
index := int16(0)
|
||||
w10, w11 := wf1[0], wf1[1]
|
||||
w20, w21 := wf2[0], wf2[1]
|
||||
aux1 := int32(lsfR1[0]) * int32(w10)
|
||||
aux2 := int32(lsfR1[1]) * int32(w11)
|
||||
aux3 := int32(lsfR2[0]) * int32(w20)
|
||||
aux4 := int32(lsfR2[1]) * int32(w21)
|
||||
|
||||
for i := 0; i < dicoSize; i++ {
|
||||
row := dico[i*4 : i*4+4] // hoist the per-dim bounds checks
|
||||
temp := int16((aux1 - int32(w10)*int32(row[0])) >> 15)
|
||||
dist := int32(temp) * int32(temp)
|
||||
if dist >= distMin {
|
||||
continue
|
||||
}
|
||||
temp = int16((aux2 - int32(w11)*int32(row[1])) >> 15)
|
||||
dist += int32(temp) * int32(temp)
|
||||
if dist >= distMin {
|
||||
continue
|
||||
}
|
||||
temp = int16((aux3 - int32(w20)*int32(row[2])) >> 15)
|
||||
dist += int32(temp) * int32(temp)
|
||||
if dist >= distMin {
|
||||
continue
|
||||
}
|
||||
temp = int16((aux4 - int32(w21)*int32(row[3])) >> 15)
|
||||
dist += int32(temp) * int32(temp)
|
||||
if dist < distMin {
|
||||
distMin = dist
|
||||
index = int16(i)
|
||||
}
|
||||
}
|
||||
|
||||
pd := int(index) << 2
|
||||
lsfR1[0] = dico[pd]
|
||||
lsfR1[1] = dico[pd+1]
|
||||
lsfR2[0] = dico[pd+2]
|
||||
lsfR2[1] = dico[pd+3]
|
||||
return index
|
||||
}
|
||||
|
||||
// vqSubvecS is vqSubvec with sign selection: each codebook entry is tried as-is
|
||||
// and negated; the index LSB encodes the sign. Mirrors Vq_subvec_s.
|
||||
func vqSubvecS(lsfR1, lsfR2, dico, wf1, wf2 []int16, dicoSize int) int16 {
|
||||
distMin := int32(maxInt32)
|
||||
index := int16(0)
|
||||
sign := int16(0)
|
||||
l10, l11 := lsfR1[0], lsfR1[1]
|
||||
l20, l21 := lsfR2[0], lsfR2[1]
|
||||
w10, w11 := wf1[0], wf1[1]
|
||||
w20, w21 := wf2[0], wf2[1]
|
||||
|
||||
for i := 0; i < dicoSize; i++ {
|
||||
row := dico[i*4 : i*4+4] // hoist the per-dim bounds checks
|
||||
temp := row[0]
|
||||
t1 := int16((int32(w10) * int32(l10-temp)) >> 15)
|
||||
t2 := int16((int32(w10) * int32(l10+temp)) >> 15)
|
||||
dist1 := int32(t1) * int32(t1)
|
||||
dist2 := int32(t2) * int32(t2)
|
||||
|
||||
temp = row[1]
|
||||
t1 = int16((int32(w11) * int32(l11-temp)) >> 15)
|
||||
t2 = int16((int32(w11) * int32(l11+temp)) >> 15)
|
||||
dist1 += int32(t1) * int32(t1)
|
||||
dist2 += int32(t2) * int32(t2)
|
||||
|
||||
if dist1 >= distMin && dist2 >= distMin {
|
||||
continue
|
||||
}
|
||||
|
||||
temp = row[2]
|
||||
t1 = int16((int32(w20) * int32(l20-temp)) >> 15)
|
||||
t2 = int16((int32(w20) * int32(l20+temp)) >> 15)
|
||||
dist1 += int32(t1) * int32(t1)
|
||||
dist2 += int32(t2) * int32(t2)
|
||||
|
||||
temp = row[3]
|
||||
t1 = int16((int32(w21) * int32(l21-temp)) >> 15)
|
||||
t2 = int16((int32(w21) * int32(l21+temp)) >> 15)
|
||||
dist1 += int32(t1) * int32(t1)
|
||||
dist2 += int32(t2) * int32(t2)
|
||||
|
||||
if dist1 < distMin {
|
||||
distMin = dist1
|
||||
index = int16(i)
|
||||
sign = 0
|
||||
}
|
||||
if dist2 < distMin {
|
||||
distMin = dist2
|
||||
index = int16(i)
|
||||
sign = 1
|
||||
}
|
||||
}
|
||||
|
||||
pd := int(index) << 2
|
||||
index <<= 1
|
||||
if sign != 0 {
|
||||
lsfR1[0] = -dico[pd]
|
||||
lsfR1[1] = -dico[pd+1]
|
||||
lsfR2[0] = -dico[pd+2]
|
||||
lsfR2[1] = -dico[pd+3]
|
||||
index++
|
||||
} else {
|
||||
lsfR1[0] = dico[pd]
|
||||
lsfR1[1] = dico[pd+1]
|
||||
lsfR2[0] = dico[pd+2]
|
||||
lsfR2[1] = dico[pd+3]
|
||||
}
|
||||
return index
|
||||
}
|
||||
|
||||
// qPlsf5 quantizes two LSP vectors (MR122) into five indices and the two
|
||||
// quantized LSP vectors, updating the predictor. The exact encoder counterpart
|
||||
// of dPlsf5. Mirrors Q_plsf_5.
|
||||
func (st *qPlsfState) qPlsf5(lsp1, lsp2, lsp1q, lsp2q []int16) [5]int16 {
|
||||
var lsf1, lsf2, wf1, wf2, lsfP, lsfR1, lsfR2, lsf1q, lsf2q [cM]int16
|
||||
|
||||
lspLsf(lsp1, lsf1[:], cM)
|
||||
lspLsf(lsp2, lsf2[:], cM)
|
||||
lsfWt(lsf1[:], wf1[:])
|
||||
lsfWt(lsf2[:], wf2[:])
|
||||
|
||||
for i := 0; i < cM; i++ {
|
||||
lsfP[i] = mean_lsf_5[i] + int16((int32(st.pastRQ[i])*cLSP_PRED_FAC_MR122)>>15)
|
||||
lsfR1[i] = lsf1[i] - lsfP[i]
|
||||
lsfR2[i] = lsf2[i] - lsfP[i]
|
||||
}
|
||||
|
||||
var indice [5]int16
|
||||
indice[0] = vqSubvec(lsfR1[0:], lsfR2[0:], dico1_lsf_5, wf1[0:], wf2[0:], cDICO1_5_SIZE)
|
||||
indice[1] = vqSubvec(lsfR1[2:], lsfR2[2:], dico2_lsf_5, wf1[2:], wf2[2:], cDICO2_5_SIZE)
|
||||
indice[2] = vqSubvecS(lsfR1[4:], lsfR2[4:], dico3_lsf_5, wf1[4:], wf2[4:], cDICO3_5_SIZE)
|
||||
indice[3] = vqSubvec(lsfR1[6:], lsfR2[6:], dico4_lsf_5, wf1[6:], wf2[6:], cDICO4_5_SIZE)
|
||||
indice[4] = vqSubvec(lsfR1[8:], lsfR2[8:], dico5_lsf_5, wf1[8:], wf2[8:], cDICO5_5_SIZE)
|
||||
|
||||
for i := 0; i < cM; i++ {
|
||||
lsf1q[i] = lsfR1[i] + lsfP[i]
|
||||
lsf2q[i] = lsfR2[i] + lsfP[i]
|
||||
st.pastRQ[i] = lsfR2[i]
|
||||
}
|
||||
|
||||
reorderLsf(lsf1q[:], cLSF_GAP, cM)
|
||||
reorderLsf(lsf2q[:], cLSF_GAP, cM)
|
||||
lsfLsp(lsf1q[:], lsp1q, cM)
|
||||
lsfLsp(lsf2q[:], lsp2q, cM)
|
||||
return indice
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
package amrnb
|
||||
|
||||
// Multi-pulse algebraic codebook search, ported from opencore-amrnb s10_8pf.cpp
|
||||
// (search_10and8i40). This parameterized depth-first search places 8 (MR102) or
|
||||
// 10 (MR122) pulses, two tracks at a time, using a precomputed interleaved
|
||||
// scratch (temp1) to cache the partial ps/alp values of the second pulse of each
|
||||
// pair across the first pulse's positions. The pulse-track ordering (ipos) is
|
||||
// rotated across the outer loop. The single most intricate function in the
|
||||
// codec; the exact incremental criterion arithmetic is preserved (bit-exact).
|
||||
func search10and8i40(nbPulse, step, nbTracks int16, dn, rr, ipos, posMax, codvec []int16) {
|
||||
const L = cL_CODE
|
||||
gsmefr := nbPulse == 10
|
||||
|
||||
var index [10]int16
|
||||
var temp1 [2 * cL_CODE]int16
|
||||
|
||||
i0 := posMax[ipos[0]]
|
||||
index[0] = i0
|
||||
|
||||
psk := int16(-1)
|
||||
alpk := int16(1)
|
||||
for i := int16(0); i < nbPulse; i++ {
|
||||
codvec[i] = i
|
||||
}
|
||||
|
||||
var i1, i2, i3, i4, i5, i6, i7 int16
|
||||
|
||||
for outer := int16(1); outer < nbTracks; outer++ {
|
||||
i1 = posMax[ipos[1]]
|
||||
index[1] = i1
|
||||
|
||||
ps0 := int16(int32(dn[i0]) + int32(dn[i1]))
|
||||
alp0 := int32(rr[int(i0)*L+int(i0)]) << 12
|
||||
alp0 += int32(rr[int(i1)*L+int(i1)]) << 12
|
||||
alp0 += int32(rr[int(i0)*L+int(i1)]) << 13
|
||||
alp0 += 0x8000
|
||||
|
||||
// ---- pulses 2 & 3 ----
|
||||
ti := 0
|
||||
for i3v := ipos[3]; i3v < L; i3v += step {
|
||||
rrRow := rr[int(i3v)*L : int(i3v)*L+L]
|
||||
s := int32(rrRow[int(i3v)]) >> 1
|
||||
s += int32(rrRow[int(i0)])
|
||||
s += int32(rrRow[int(i1)])
|
||||
temp1[ti] = ps0 + dn[i3v]
|
||||
temp1[ti+1] = int16((s + 2) >> 2)
|
||||
ti += 2
|
||||
}
|
||||
|
||||
sq := int16(-1)
|
||||
alp := int16(1)
|
||||
ps := int16(0)
|
||||
ia := ipos[2]
|
||||
ib := ipos[3]
|
||||
sbase := alp0 >> 12
|
||||
for j := ipos[2]; j < L; j += step {
|
||||
rrRow := rr[int(j)*L : int(j)*L+L]
|
||||
alp1 := (sbase + int32(rrRow[int(j)])) >> 1
|
||||
alp1 += int32(rrRow[int(i0)])
|
||||
alp1 += int32(rrRow[int(i1)])
|
||||
ps1 := dn[j]
|
||||
ti = 0
|
||||
for i3v := ipos[3]; i3v < L; i3v += step {
|
||||
ps2 := ps1 + temp1[ti]
|
||||
sq2 := int16((int32(ps2) * int32(ps2)) >> 15)
|
||||
alp2 := (alp1 + int32(rrRow[int(i3v)])) >> 2
|
||||
alp2 = (alp2 + int32(temp1[ti+1])) >> 1
|
||||
ti += 2
|
||||
if int32(sq2)*int32(alp) > int32(sq)*alp2 {
|
||||
sq, ps, alp, ia, ib = sq2, ps2, int16(alp2), j, i3v
|
||||
}
|
||||
}
|
||||
}
|
||||
i2, i3 = ia, ib
|
||||
index[2], index[3] = ia, ib
|
||||
|
||||
// ---- pulses 4 & 5 ----
|
||||
alp0 = (int32(alp) << 15) + 0x8000
|
||||
ti = 0
|
||||
for i5v := ipos[5]; i5v < L; i5v += step {
|
||||
rrRow := rr[int(i5v)*L : int(i5v)*L+L]
|
||||
s := int32(rrRow[int(i5v)]) >> 1
|
||||
s += int32(rrRow[int(i0)]) + int32(rrRow[int(i1)]) + int32(rrRow[int(i2)]) + int32(rrRow[int(i3)])
|
||||
temp1[ti] = ps + dn[i5v]
|
||||
temp1[ti+1] = int16((s + 2) >> 2)
|
||||
ti += 2
|
||||
}
|
||||
sq, alp, ps, ia, ib = -1, 1, 0, ipos[4], ipos[5]
|
||||
for j := ipos[4]; j < L; j += step {
|
||||
rrRow := rr[int(j)*L : int(j)*L+L]
|
||||
alp1 := alp0 + (int32(rrRow[int(j)]) << 11)
|
||||
alp1 += int32(rrRow[int(i0)]) << 12
|
||||
alp1 += int32(rrRow[int(i1)]) << 12
|
||||
alp1 += int32(rrRow[int(i2)]) << 12
|
||||
alp1 += int32(rrRow[int(i3)]) << 12
|
||||
ps1 := dn[j]
|
||||
ti = 0
|
||||
for i5v := ipos[5]; i5v < L; i5v += step {
|
||||
ps2 := ps1 + temp1[ti]
|
||||
alp2 := alp1 + (int32(rrRow[int(i5v)]) << 12)
|
||||
alp16 := int16((alp2 + (int32(temp1[ti+1]) << 14)) >> 16)
|
||||
ti += 2
|
||||
sq2 := int16((int32(ps2) * int32(ps2)) >> 15)
|
||||
if int32(sq2)*int32(alp) > int32(sq)*int32(alp16) {
|
||||
sq, ps, alp, ia, ib = sq2, ps2, alp16, j, i5v
|
||||
}
|
||||
}
|
||||
}
|
||||
i4, i5 = ia, ib
|
||||
index[4], index[5] = ia, ib
|
||||
|
||||
// ---- pulses 6 & 7 ----
|
||||
alp0 = (int32(alp) << 15) + 0x8000
|
||||
ti = 0
|
||||
for i7v := ipos[7]; i7v < L; i7v += step {
|
||||
rrRow := rr[int(i7v)*L : int(i7v)*L+L]
|
||||
s := int32(rrRow[int(i7v)]) >> 1
|
||||
s += int32(rrRow[int(i0)]) + int32(rrRow[int(i1)]) + int32(rrRow[int(i2)]) +
|
||||
int32(rrRow[int(i3)]) + int32(rrRow[int(i4)]) + int32(rrRow[int(i5)])
|
||||
temp1[ti] = ps + dn[i7v]
|
||||
temp1[ti+1] = int16((s + 4) >> 3)
|
||||
ti += 2
|
||||
}
|
||||
sq, alp, ps, ia, ib = -1, 1, 0, ipos[6], ipos[7]
|
||||
for j := ipos[6]; j < L; j += step {
|
||||
rrRow := rr[int(j)*L : int(j)*L+L]
|
||||
alp1 := alp0 + (int32(rrRow[int(j)]) << 10)
|
||||
alp1 += int32(rrRow[int(i0)]) << 11
|
||||
alp1 += int32(rrRow[int(i1)]) << 11
|
||||
alp1 += int32(rrRow[int(i2)]) << 11
|
||||
alp1 += int32(rrRow[int(i3)]) << 11
|
||||
alp1 += int32(rrRow[int(i4)]) << 11
|
||||
alp1 += int32(rrRow[int(i5)]) << 11
|
||||
ps1 := dn[j]
|
||||
ti = 0
|
||||
for i7v := ipos[7]; i7v < L; i7v += step {
|
||||
ps2 := ps1 + temp1[ti]
|
||||
alp2 := alp1 + (int32(rrRow[int(i7v)]) << 11)
|
||||
alp16 := int16((alp2 + (int32(temp1[ti+1]) << 14)) >> 16)
|
||||
ti += 2
|
||||
sq2 := int16((int32(ps2) * int32(ps2)) >> 15)
|
||||
if int32(sq2)*int32(alp) > int32(sq)*int32(alp16) {
|
||||
sq, ps, alp, ia, ib = sq2, ps2, alp16, j, i7v
|
||||
}
|
||||
}
|
||||
}
|
||||
i6, i7 = ia, ib
|
||||
index[6], index[7] = ia, ib
|
||||
|
||||
// ---- pulses 8 & 9 (MR122 only) ----
|
||||
if gsmefr {
|
||||
alp0 = (int32(alp) << 15) + 0x8000
|
||||
ti = 0
|
||||
for i9v := ipos[9]; i9v < L; i9v += step {
|
||||
rrRow := rr[int(i9v)*L : int(i9v)*L+L]
|
||||
s := int32(rrRow[int(i9v)]) >> 1
|
||||
s += int32(rrRow[int(i0)]) + int32(rrRow[int(i1)]) + int32(rrRow[int(i2)]) +
|
||||
int32(rrRow[int(i3)]) + int32(rrRow[int(i4)]) + int32(rrRow[int(i5)]) +
|
||||
int32(rrRow[int(i6)]) + int32(rrRow[int(i7)])
|
||||
temp1[ti] = ps + dn[i9v]
|
||||
temp1[ti+1] = int16((s + 4) >> 3)
|
||||
ti += 2
|
||||
}
|
||||
sq, alp, ps, ia, ib = -1, 1, 0, ipos[8], ipos[9]
|
||||
for j := ipos[8]; j < L; j += step {
|
||||
rrRow := rr[int(j)*L : int(j)*L+L]
|
||||
alp1 := alp0 + (int32(rrRow[int(j)]) << 9)
|
||||
alp1 += int32(rr[int(i0)*L+int(j)]) << 10
|
||||
alp1 += int32(rr[int(i1)*L+int(j)]) << 10
|
||||
alp1 += int32(rr[int(i2)*L+int(j)]) << 10
|
||||
alp1 += int32(rr[int(i3)*L+int(j)]) << 10
|
||||
alp1 += int32(rr[int(i4)*L+int(j)]) << 10
|
||||
alp1 += int32(rr[int(i5)*L+int(j)]) << 10
|
||||
alp1 += int32(rr[int(i6)*L+int(j)]) << 10
|
||||
alp1 += int32(rr[int(i7)*L+int(j)]) << 10
|
||||
ps1 := dn[j]
|
||||
ti = 0
|
||||
for i9v := ipos[9]; i9v < L; i9v += step {
|
||||
ps2 := ps1 + temp1[ti]
|
||||
sq2 := int16((int32(ps2) * int32(ps2)) >> 15)
|
||||
alp2 := alp1 + (int32(rrRow[int(i9v)]) << 10)
|
||||
alp16 := int16((alp2 + (int32(temp1[ti+1]) << 13)) >> 16)
|
||||
ti += 2
|
||||
if int32(sq2)*int32(alp) > int32(sq)*int32(alp16) {
|
||||
sq, ps, alp, ia, ib = sq2, ps2, alp16, j, i9v
|
||||
}
|
||||
}
|
||||
}
|
||||
index[8], index[9] = ia, ib
|
||||
}
|
||||
|
||||
// ---- keep the best ----
|
||||
if int32(alpk)*int32(sq) > int32(psk)*int32(alp) {
|
||||
psk = sq
|
||||
alpk = alp
|
||||
copy(codvec[:nbPulse], index[:nbPulse])
|
||||
}
|
||||
|
||||
// rotate ipos[1..nbPulse-1] left by one
|
||||
pos := ipos[1]
|
||||
for j := int16(1); j < nbPulse-1; j++ {
|
||||
ipos[j] = ipos[j+1]
|
||||
}
|
||||
ipos[nbPulse-1] = pos
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package amrnb
|
||||
|
||||
// Per-subframe codebook dispatch and post-processing, ported from opencore-amrnb
|
||||
// cbsearch.cpp (cbsearch) and spstproc.cpp (subframePostProc). cbsearch routes
|
||||
// to the mode's algebraic codebook search (and applies the MR102/MR122 pitch
|
||||
// sharpening around it); subframePostProc forms the total excitation, runs the
|
||||
// local synthesis, and updates the synthesis/error/weighting filter memories
|
||||
// for the next subframe. Bit-exact with the reference.
|
||||
|
||||
// cbsearch runs the fixed-codebook search for the mode, writing the innovation
|
||||
// code and filtered code y and the analysis indices into anap (returning the
|
||||
// count). Mirrors cbsearch.
|
||||
func cbsearch(x, h []int16, T0, pitchSharp, gainPit int16, res2, code, y []int16, mode, subNr int, anap []int16) int {
|
||||
switch {
|
||||
case mode == dMR475 || mode == dMR515:
|
||||
idx, sgn := code2i40_9bits(int16(subNr), x, h, T0, pitchSharp, code, y)
|
||||
anap[0], anap[1] = idx, sgn
|
||||
return 2
|
||||
case mode == dMR59:
|
||||
idx, sgn := code2i40_11bits(x, h, T0, pitchSharp, code, y)
|
||||
anap[0], anap[1] = idx, sgn
|
||||
return 2
|
||||
case mode == dMR67:
|
||||
idx, sgn := code3i40_14bits(x, h, T0, pitchSharp, code, y)
|
||||
anap[0], anap[1] = idx, sgn
|
||||
return 2
|
||||
case mode == dMR74 || mode == dMR795:
|
||||
idx, sgn := code4i40_17bits(x, h, T0, pitchSharp, code, y)
|
||||
anap[0], anap[1] = idx, sgn
|
||||
return 2
|
||||
case mode == dMR102:
|
||||
ps := shl(pitchSharp, 1)
|
||||
for i := T0; i < cL_SUBFR; i++ {
|
||||
h[i] = add(h[i], mult(h[i-T0], ps))
|
||||
}
|
||||
code8i40_31bits(x, res2, h, code, y, anap[0:7])
|
||||
for i := T0; i < cL_SUBFR; i++ {
|
||||
code[i] = add(code[i], mult(code[i-T0], ps))
|
||||
}
|
||||
return 7
|
||||
default: // MR122
|
||||
ps := shl(gainPit, 1)
|
||||
for i := T0; i < cL_SUBFR; i++ {
|
||||
h[i] = add(h[i], int16((int32(h[i-T0])*int32(ps))>>15))
|
||||
}
|
||||
code10i40_35bits(x, res2, h, code, y, anap[0:10])
|
||||
for i := T0; i < cL_SUBFR; i++ {
|
||||
code[i] = add(code[i], mult(code[i-T0], ps))
|
||||
}
|
||||
return 10
|
||||
}
|
||||
}
|
||||
|
||||
// subframePostProc builds the total excitation (gain_pit·adaptive +
|
||||
// gain_code·code), runs the local synthesis (updating mem_syn), and refreshes
|
||||
// the error and weighting-filter memories. sharp is updated with the clamped
|
||||
// pitch gain. Mirrors subframePostProc.
|
||||
func subframePostProc(speech []int16, speechOff, mode, iSubfr int, gainPit, gainCode int16, aq, synth, xn, code, y1, y2, memSyn, memErr, memW0, exc []int16, excOff int, sharp *int16) {
|
||||
var tempShift, kShift, pitchFac int16
|
||||
if mode != dMR122 {
|
||||
tempShift, kShift, pitchFac = 1, 16-2-1, gainPit
|
||||
} else {
|
||||
tempShift, kShift, pitchFac = 2, 16-4-1, gainPit>>1
|
||||
}
|
||||
|
||||
if gainPit < cSHARPMAX {
|
||||
*sharp = gainPit
|
||||
} else {
|
||||
*sharp = cSHARPMAX
|
||||
}
|
||||
|
||||
base := excOff + iSubfr
|
||||
for i := 0; i < cL_SUBFR; i++ {
|
||||
L := (int32(exc[base+i]) * int32(pitchFac)) << 1
|
||||
L += (int32(code[i]) * int32(gainCode)) << 1
|
||||
L <<= uint(tempShift)
|
||||
exc[base+i] = int16((L + 0x8000) >> 16)
|
||||
}
|
||||
|
||||
synFilt(aq, exc[base:base+cL_SUBFR], synth[iSubfr:iSubfr+cL_SUBFR], cL_SUBFR, memSyn, true)
|
||||
|
||||
for i, j := cL_SUBFR-cM, 0; i < cL_SUBFR; i, j = i+1, j+1 {
|
||||
memErr[j] = speech[speechOff+iSubfr+i] - synth[iSubfr+i]
|
||||
temp := int16((int32(y1[i]) * int32(gainPit)) >> 14)
|
||||
temp += int16((int32(y2[i]) * int32(gainCode)) >> uint(kShift))
|
||||
memW0[j] = xn[i] - temp
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
package amrnb
|
||||
|
||||
// Fixed-codebook gain prediction, ported from opencore-amrnb gc_pred.cpp plus
|
||||
// the 32-bit composite operators it needs (L_Extract, L_Comp, Mpy_32_16 from
|
||||
// the ETSI basicop set). gc_pred runs the MA energy predictor that yields the
|
||||
// predicted code gain (gcode0) used by the gain dequantizers; gc_pred_update
|
||||
// feeds back the quantized energy each subframe. Bit-exact with the reference.
|
||||
|
||||
const (
|
||||
cNPRED = 4
|
||||
cMEAN_ENER_MR122 = 783741 // Q17
|
||||
cMIN_ENERGY = -14336 // Q10
|
||||
cMIN_ENERGY_MR122 = -2381 // Q10
|
||||
)
|
||||
|
||||
// MA prediction coefficients (gc_pred.cpp).
|
||||
var gcPred = [cNPRED]int16{5571, 4751, 2785, 1556}
|
||||
var gcPredMR122 = [cNPRED]int16{44, 37, 22, 12}
|
||||
|
||||
// L_Extract splits a 32-bit value into a 16-bit high part and a 15-bit low
|
||||
// part such that L ≈ (hi<<16) + (lo<<1). Mirrors L_Extract.
|
||||
func L_Extract(L int32) (hi, lo int16) {
|
||||
hi = int16(L >> 16)
|
||||
lo = int16((L >> 1) - (int32(hi) << 15))
|
||||
return hi, lo
|
||||
}
|
||||
|
||||
// L_Comp recombines a (hi,lo) pair back into a 32-bit value. Mirrors L_Comp.
|
||||
func L_Comp(hi, lo int16) int32 {
|
||||
return L_mac(L_deposit_h(hi), lo, 1)
|
||||
}
|
||||
|
||||
// mpy32_16 multiplies a 32-bit value (given as hi,lo) by a 16-bit value,
|
||||
// matching the optimized opencore-amrnb Mpy_32_16 (truncated low-part shift).
|
||||
func mpy32_16(hi, lo, n int16) int32 {
|
||||
return L_add(L_mult(hi, n), ((int32(lo)*int32(n))>>15)<<1)
|
||||
}
|
||||
|
||||
// gcPredState is the MA energy-predictor memory (two parallel histories: the
|
||||
// 20·log10 form for most modes and the log2 form for MR122). Mirrors
|
||||
// gc_predState.
|
||||
type gcPredState struct {
|
||||
pastQuaEn [cNPRED]int16 // Q10, 20*log10(qua_err)
|
||||
pastQuaEnMR122 [cNPRED]int16 // Q10, log2(qua_err)
|
||||
}
|
||||
|
||||
// reset initializes both predictor histories to their energy floor. Mirrors
|
||||
// gc_pred_reset.
|
||||
func (st *gcPredState) reset() {
|
||||
for i := 0; i < cNPRED; i++ {
|
||||
st.pastQuaEn[i] = cMIN_ENERGY
|
||||
st.pastQuaEnMR122[i] = cMIN_ENERGY_MR122
|
||||
}
|
||||
}
|
||||
|
||||
// update shifts the new quantized energies into the predictor memory. Mirrors
|
||||
// gc_pred_update.
|
||||
func (st *gcPredState) update(quaEnerMR122, quaEner int16) {
|
||||
st.pastQuaEn[3] = st.pastQuaEn[2]
|
||||
st.pastQuaEnMR122[3] = st.pastQuaEnMR122[2]
|
||||
st.pastQuaEn[2] = st.pastQuaEn[1]
|
||||
st.pastQuaEnMR122[2] = st.pastQuaEnMR122[1]
|
||||
st.pastQuaEn[1] = st.pastQuaEn[0]
|
||||
st.pastQuaEnMR122[1] = st.pastQuaEnMR122[0]
|
||||
st.pastQuaEnMR122[0] = quaEnerMR122
|
||||
st.pastQuaEn[0] = quaEner
|
||||
}
|
||||
|
||||
// gcPredResult carries gc_pred's outputs: the exponent/fraction of the
|
||||
// predicted gain factor gcode0, and (MR795 only) of the innovation energy.
|
||||
type gcPredResult struct {
|
||||
expGcode0, fracGcode0 int16
|
||||
expEn, fracEn int16
|
||||
}
|
||||
|
||||
// gcPred computes the predicted fixed-codebook gain factor from the innovation
|
||||
// energy and the predictor memory. Mirrors gc_pred (gc_pred.cpp).
|
||||
func (st *gcPredState) gcPred(mode int, code []int16) gcPredResult {
|
||||
var r gcPredResult
|
||||
|
||||
var enerCode int32
|
||||
for i := cL_SUBFR >> 2; i != 0; i-- {
|
||||
base := (cL_SUBFR>>2 - i) * 4
|
||||
for k := 0; k < 4; k++ {
|
||||
tmp := code[base+k]
|
||||
enerCode += (int32(tmp) * int32(tmp)) >> 3
|
||||
}
|
||||
}
|
||||
enerCode <<= 4
|
||||
if enerCode>>31 != 0 { // saturation
|
||||
enerCode = maxInt32
|
||||
}
|
||||
|
||||
if mode == dMR122 {
|
||||
enerCode = int32(round_(enerCode)) * 26214 << 1
|
||||
exp, frac := log2(enerCode)
|
||||
lTemp1 := int32(exp-30) << 16
|
||||
enerCode = lTemp1 + (int32(frac) << 1)
|
||||
|
||||
ener := int32(cMEAN_ENER_MR122)
|
||||
for i := 0; i < cNPRED; i++ {
|
||||
lt := (int32(st.pastQuaEnMR122[i]) * int32(gcPredMR122[i])) << 1
|
||||
ener = L_add(ener, lt)
|
||||
}
|
||||
|
||||
lTemp1 = L_sub(ener, enerCode)
|
||||
r.expGcode0 = int16(lTemp1 >> 17)
|
||||
lTemp2 := int32(r.expGcode0) << 15
|
||||
lTemp1 >>= 2
|
||||
r.fracGcode0 = int16(lTemp1 - lTemp2)
|
||||
return r
|
||||
}
|
||||
|
||||
// all modes except 12.2
|
||||
expCode := norm_l(enerCode)
|
||||
enerCode = L_shl(enerCode, expCode)
|
||||
exp, frac := log2Norm(enerCode, expCode)
|
||||
|
||||
lTemp2 := (int32(exp) * -24660) << 1
|
||||
lTmp := (int32(frac) * -24660) >> 15
|
||||
if lTmp&0x00010000 != 0 { // sign-extend
|
||||
lTmp |= int32(-0x10000) // 0xffff0000
|
||||
}
|
||||
lTmp <<= 1
|
||||
lTmp = L_add(lTmp, lTemp2)
|
||||
|
||||
switch mode {
|
||||
case dMR102:
|
||||
lTemp2 = int32(16678) << 7
|
||||
lTmp = L_add(lTmp, lTemp2)
|
||||
case dMR795:
|
||||
r.fracEn = int16(enerCode >> 16)
|
||||
r.expEn = int16(-11 - expCode)
|
||||
lTemp2 = int32(17062) << 7
|
||||
lTmp = L_add(lTmp, lTemp2)
|
||||
case dMR74:
|
||||
lTemp2 = int32(32588) << 6
|
||||
lTmp = L_add(lTmp, lTemp2)
|
||||
case dMR67:
|
||||
lTemp2 = int32(32268) << 6
|
||||
lTmp = L_add(lTmp, lTemp2)
|
||||
default: // MR59, MR515, MR475
|
||||
lTemp2 = int32(16678) << 7
|
||||
lTmp = L_add(lTmp, lTemp2)
|
||||
}
|
||||
|
||||
// gcode0 = sum(pred[i]*past_qua_en[i]) - ener_code + mean_ener (Q24)
|
||||
if lTmp > 0x001fffff {
|
||||
lTmp = maxInt32
|
||||
} else if lTmp < -2097152 {
|
||||
lTmp = minInt32
|
||||
} else {
|
||||
lTmp <<= 10
|
||||
}
|
||||
for i := 0; i < 4; i++ {
|
||||
lTemp2 = (int32(gcPred[i]) * int32(st.pastQuaEn[i])) << 1
|
||||
lTmp = L_add(lTmp, lTemp2)
|
||||
}
|
||||
gcode0 := int16(lTmp >> 16) // Q8
|
||||
|
||||
// gcode0 = pow(2, 0.166*gcode0)
|
||||
if mode == dMR74 { // IS641 bit-exactness
|
||||
lTmp = int32(gcode0) * 5439 << 1
|
||||
} else {
|
||||
lTmp = int32(gcode0) * 5443 << 1
|
||||
}
|
||||
if lTmp < 0 {
|
||||
lTmp = ^((^lTmp) >> 8)
|
||||
} else {
|
||||
lTmp >>= 8 // -> Q16
|
||||
}
|
||||
r.expGcode0 = int16(lTmp >> 16)
|
||||
var lTemp1 int32
|
||||
if lTmp < 0 {
|
||||
lTemp1 = ^((^lTmp) >> 1)
|
||||
} else {
|
||||
lTemp1 = lTmp >> 1
|
||||
}
|
||||
lTemp2 = int32(r.expGcode0) << 15
|
||||
r.fracGcode0 = int16(L_sub(lTemp1, lTemp2))
|
||||
return r
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
package amrnb
|
||||
|
||||
// LSP/LSF conversions and interpolation, ported function-by-function from the
|
||||
// opencore-amrnb common sources (lsp_az.cpp, lsp_lsf.cpp, int_lpc.cpp). These
|
||||
// turn the decoded line-spectral representation into the per-subframe LP
|
||||
// synthesis coefficients A(z) (order 10). Bit-exact with the reference.
|
||||
|
||||
// getLspPol finds the coefficients of F1(z) or F2(z) from the (cosine-domain)
|
||||
// LSPs by expanding the product polynomial. f must have length 6. Mirrors
|
||||
// Get_lsp_pol (lsp_az.cpp).
|
||||
func getLspPol(lsp []int16, f []int32) {
|
||||
fi := 0
|
||||
li := 0
|
||||
f[fi] = 0x01000000 // f[0] = 1.0
|
||||
fi++
|
||||
f[fi] = (-int32(lsp[li])) << 10 // f[1] = -2.0 * lsp[0]
|
||||
fi++
|
||||
li++
|
||||
li++ // advance lsp pointer
|
||||
|
||||
for i := int16(2); i <= 5; i++ {
|
||||
f[fi] = f[fi-2]
|
||||
for j := int16(1); j < i; j++ {
|
||||
hi := int16(f[fi-1] >> 16)
|
||||
lo := int16((f[fi-1] >> 1) - (int32(hi) << 15))
|
||||
t0 := int32(hi) * int32(lsp[li])
|
||||
t0 += (int32(lo) * int32(lsp[li])) >> 15
|
||||
f[fi] += f[fi-2]
|
||||
f[fi] -= t0 << 2
|
||||
fi--
|
||||
}
|
||||
f[fi] -= int32(lsp[li]) << 10
|
||||
li++
|
||||
fi += int(i)
|
||||
li++
|
||||
}
|
||||
}
|
||||
|
||||
// lspAz converts line spectral pairs to order-10 LP coefficients a[0:11].
|
||||
// Mirrors Lsp_Az (lsp_az.cpp).
|
||||
func lspAz(lsp []int16, a []int16) {
|
||||
var f1, f2 [6]int32
|
||||
getLspPol(lsp[0:], f1[:])
|
||||
getLspPol(lsp[1:], f2[:])
|
||||
for i := 5; i > 0; i-- {
|
||||
f1[i] += f1[i-1]
|
||||
f2[i] -= f2[i-1]
|
||||
}
|
||||
a[0] = 4096
|
||||
for i, j := 1, 10; i <= 5; i, j = i+1, j-1 {
|
||||
t0 := f1[i] + f2[i]
|
||||
t1 := f1[i] - f2[i]
|
||||
t0 += 1 << 12
|
||||
t1 += 1 << 12
|
||||
a[i] = int16(t0 >> 13)
|
||||
a[j] = int16(t1 >> 13)
|
||||
}
|
||||
}
|
||||
|
||||
// lsfLsp converts normalized LSFs (Q15, 0..0.5) to LSPs (cosine domain) by
|
||||
// table lookup and interpolation. Mirrors Lsf_lsp (lsp_lsf.cpp).
|
||||
func lsfLsp(lsf, lsp []int16, m int16) {
|
||||
for i := int16(0); i < m; i++ {
|
||||
ind := lsf[i] >> 8 // b8-b15
|
||||
offset := lsf[i] & 0x00ff // b0-b7
|
||||
L_tmp := (int32(lspLsfTable[ind+1]) - int32(lspLsfTable[ind])) * int32(offset) >> 8
|
||||
lsp[i] = lspLsfTable[ind] + int16(L_tmp)
|
||||
}
|
||||
}
|
||||
|
||||
// lspLsf converts LSPs (cosine domain) to normalized LSFs (Q15) via the acos
|
||||
// table and per-segment slope. Mirrors Lsp_lsf (lsp_lsf.cpp).
|
||||
func lspLsf(lsp, lsf []int16, m int16) {
|
||||
ind := int16(63)
|
||||
for i := m - 1; i >= 0; i-- {
|
||||
temp := lsp[i]
|
||||
for lspLsfTable[ind] < temp {
|
||||
ind--
|
||||
}
|
||||
L_tmp := (int32(temp) - int32(lspLsfTable[ind])) * int32(lspLsfSlope[ind])
|
||||
L_tmp = (L_tmp + 0x800) >> 12
|
||||
lsf[i] = int16(L_tmp) + (ind << 8)
|
||||
}
|
||||
}
|
||||
|
||||
// intLpc1and3 interpolates LSPs across the four subframes (old/mid/new LSP
|
||||
// sets) and produces A(z) for each, into Az (length 4*cMP1). Used by modes that
|
||||
// transmit a mid-frame LSP set. Mirrors Int_lpc_1and3 (int_lpc.cpp).
|
||||
func intLpc1and3(lspOld, lspMid, lspNew []int16, Az []int16) {
|
||||
var lsp [cM]int16
|
||||
for i := 0; i < cM; i++ {
|
||||
lsp[i] = (lspOld[i] >> 1) + (lspMid[i] >> 1)
|
||||
}
|
||||
lspAz(lsp[:], Az[0:]) // subframe 1
|
||||
lspAz(lspMid, Az[cMP1:]) // subframe 2
|
||||
for i := 0; i < cM; i++ {
|
||||
lsp[i] = (lspMid[i] >> 1) + (lspNew[i] >> 1)
|
||||
}
|
||||
lspAz(lsp[:], Az[2*cMP1:]) // subframe 3
|
||||
lspAz(lspNew, Az[3*cMP1:]) // subframe 4
|
||||
}
|
||||
|
||||
// intLpc1to3 interpolates between only the past-frame and present-frame LSP
|
||||
// sets (no mid set) across the four subframes. Mirrors Int_lpc_1to3.
|
||||
func intLpc1to3(lspOld, lspNew []int16, Az []int16) {
|
||||
var lsp [cM]int16
|
||||
for i := 0; i < cM; i++ {
|
||||
temp := lspOld[i] - (lspOld[i] >> 2)
|
||||
lsp[i] = temp + (lspNew[i] >> 2)
|
||||
}
|
||||
lspAz(lsp[:], Az[0:]) // subframe 1
|
||||
for i := 0; i < cM; i++ {
|
||||
lsp[i] = (lspNew[i] >> 1) + (lspOld[i] >> 1)
|
||||
}
|
||||
lspAz(lsp[:], Az[cMP1:]) // subframe 2
|
||||
for i := 0; i < cM; i++ {
|
||||
temp := lspNew[i] - (lspNew[i] >> 2)
|
||||
lsp[i] = temp + (lspOld[i] >> 2)
|
||||
}
|
||||
lspAz(lsp[:], Az[2*cMP1:]) // subframe 3
|
||||
lspAz(lspNew, Az[3*cMP1:]) // subframe 4
|
||||
}
|
||||
|
||||
// intLpc1and3_2 interpolates only subframes 1 and 3 (leaving 2 and 4 as the
|
||||
// directly-computed A_mid/A_new), used for the unquantized analysis filters.
|
||||
// Mirrors Int_lpc_1and3_2.
|
||||
func intLpc1and3_2(lspOld, lspMid, lspNew, az []int16) {
|
||||
var lsp [cM]int16
|
||||
for i := 0; i < cM; i++ {
|
||||
lsp[i] = (lspOld[i] >> 1) + (lspMid[i] >> 1)
|
||||
}
|
||||
lspAz(lsp[:], az[0:]) // subframe 1
|
||||
for i := 0; i < cM; i++ {
|
||||
lsp[i] = (lspMid[i] >> 1) + (lspNew[i] >> 1)
|
||||
}
|
||||
lspAz(lsp[:], az[2*cMP1:]) // subframe 3
|
||||
}
|
||||
|
||||
// intLpc1to3_2 interpolates subframes 1, 2 and 3 (leaving 4 as A_new). Mirrors
|
||||
// Int_lpc_1to3_2.
|
||||
func intLpc1to3_2(lspOld, lspNew, az []int16) {
|
||||
var lsp [cM]int16
|
||||
for i := 0; i < cM; i++ {
|
||||
temp := lspOld[i] - (lspOld[i] >> 2)
|
||||
lsp[i] = temp + (lspNew[i] >> 2)
|
||||
}
|
||||
lspAz(lsp[:], az[0:]) // subframe 1
|
||||
for i := 0; i < cM; i++ {
|
||||
lsp[i] = (lspNew[i] >> 1) + (lspOld[i] >> 1)
|
||||
}
|
||||
lspAz(lsp[:], az[cMP1:]) // subframe 2
|
||||
for i := 0; i < cM; i++ {
|
||||
temp := lspNew[i] - (lspNew[i] >> 2)
|
||||
lsp[i] = temp + (lspOld[i] >> 2)
|
||||
}
|
||||
lspAz(lsp[:], az[2*cMP1:]) // subframe 3
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
package amrnb
|
||||
|
||||
// Higher-level fixed-point math operators, ported function-by-function from the
|
||||
// opencore-amrnb common sources (log2_norm.cpp, log2.cpp, pow2.cpp,
|
||||
// inv_sqrt.cpp, sqrt_l.cpp, shr_r.cpp, l_shr_r.cpp). Each uses the ROM tables
|
||||
// in tables_math.go and is bit-exact with the reference by construction.
|
||||
|
||||
// shr_r is shr with rounding: shr(var1, var2) plus 1 if the most significant
|
||||
// discarded bit is set. Mirrors shr_r.cpp.
|
||||
func shr_r(var1, var2 int16) int16 {
|
||||
if var2 > 15 {
|
||||
return 0
|
||||
}
|
||||
out := shr(var1, var2)
|
||||
if var2 > 0 {
|
||||
if var1&(int16(1)<<uint(var2-1)) != 0 {
|
||||
out = int16(out + 1) // Word16 wraparound, matching the reference
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// L_shr_r is L_shr with rounding. Mirrors l_shr_r.cpp.
|
||||
func L_shr_r(L_var1 int32, var2 int16) int32 {
|
||||
if var2 > 31 {
|
||||
return 0
|
||||
}
|
||||
result := L_shr(L_var1, var2)
|
||||
if var2 > 0 {
|
||||
if L_var1&(int32(1)<<uint(var2-1)) != 0 {
|
||||
result = result + 1 // Word32 wraparound
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// log2Norm computes Log2 of a pre-normalized value. exp is norm_l of the
|
||||
// original input; it returns the integer and fractional parts of the base-2
|
||||
// log. Mirrors Log2_norm (log2_norm.cpp).
|
||||
func log2Norm(L_x int32, exp int16) (exponent, fraction int16) {
|
||||
if L_x <= 0 {
|
||||
return 0, 0
|
||||
}
|
||||
exponent = sub(30, exp)
|
||||
L_x = L_shr(L_x, 9)
|
||||
i := extract_h(L_x) // b25-b31
|
||||
L_x = L_shr(L_x, 1)
|
||||
a := extract_l(L_x) & 0x7fff // b10-b24
|
||||
i = sub(i, 32)
|
||||
L_y := L_deposit_h(log2_tbl[i])
|
||||
tmp := sub(log2_tbl[i], log2_tbl[i+1])
|
||||
L_y = L_msu(L_y, tmp, a)
|
||||
fraction = extract_h(L_y)
|
||||
return exponent, fraction
|
||||
}
|
||||
|
||||
// log2 normalizes L_x and returns the integer and fractional parts of its
|
||||
// base-2 logarithm. Mirrors Log2 (log2.cpp).
|
||||
func log2(L_x int32) (exponent, fraction int16) {
|
||||
exp := norm_l(L_x)
|
||||
return log2Norm(L_shl(L_x, exp), exp)
|
||||
}
|
||||
|
||||
// pow2 computes 2^(exponent + fraction) in Q0..Q31. Mirrors Pow2 (pow2.cpp).
|
||||
func pow2(exponent, fraction int16) int32 {
|
||||
L_x := L_mult(fraction, 32) // fraction << 6
|
||||
i := extract_h(L_x)
|
||||
L_x = L_shr(L_x, 1)
|
||||
a := extract_l(L_x) & 0x7fff
|
||||
L_x = L_deposit_h(pow2_tbl[i])
|
||||
tmp := sub(pow2_tbl[i], pow2_tbl[i+1])
|
||||
L_x = L_msu(L_x, tmp, a)
|
||||
exp := sub(30, exponent)
|
||||
return L_shr_r(L_x, exp)
|
||||
}
|
||||
|
||||
// invSqrt returns an approximation of 1/sqrt(L_x) by table lookup and linear
|
||||
// interpolation. Mirrors Inv_sqrt (inv_sqrt.cpp).
|
||||
func invSqrt(L_x int32) int32 {
|
||||
if L_x <= 0 {
|
||||
return 0x3fffffff
|
||||
}
|
||||
exp := norm_l(L_x)
|
||||
L_x = L_shl(L_x, exp)
|
||||
exp = sub(30, exp)
|
||||
if exp&1 == 0 { // even exponent -> shift right
|
||||
L_x = L_shr(L_x, 1)
|
||||
}
|
||||
exp = shr(exp, 1)
|
||||
exp = add(exp, 1)
|
||||
L_x = L_shr(L_x, 9)
|
||||
i := extract_h(L_x)
|
||||
L_x = L_shr(L_x, 1)
|
||||
a := extract_l(L_x) & 0x7fff
|
||||
i = sub(i, 16)
|
||||
L_y := L_deposit_h(inv_sqrt_tbl[i])
|
||||
tmp := sub(inv_sqrt_tbl[i], inv_sqrt_tbl[i+1])
|
||||
L_y = L_msu(L_y, tmp, a)
|
||||
return L_shr(L_y, exp) // denormalization
|
||||
}
|
||||
|
||||
// sqrtLExp returns sqrt(L_x) together with the right shift (exp) that must be
|
||||
// applied to the result to denormalize it: the true value is the return value
|
||||
// shifted right by exp/2. Mirrors sqrt_l_exp (sqrt_l.cpp).
|
||||
func sqrtLExp(L_x int32) (result int32, exp int16) {
|
||||
if L_x <= 0 {
|
||||
return 0, 0
|
||||
}
|
||||
e := norm_l(L_x) &^ 1 // next lower even normalization exponent (clear bit 0)
|
||||
L_x = L_shl(L_x, e)
|
||||
L_x = L_shr(L_x, 9)
|
||||
i := extract_h(L_x) // 16 <= i <= 63
|
||||
L_x = L_shr(L_x, 1)
|
||||
a := extract_l(L_x) & 0x7fff
|
||||
i = sub(i, 16) // 0 <= i <= 47
|
||||
L_y := L_deposit_h(sqrt_l_tbl[i])
|
||||
tmp := sub(sqrt_l_tbl[i], sqrt_l_tbl[i+1])
|
||||
L_y = L_msu(L_y, tmp, a)
|
||||
return L_y, e
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package amrnb
|
||||
|
||||
// Output post-processing building blocks, ported from opencore-amrnb
|
||||
// weight_a.cpp (Weight_Ai), preemph.cpp (preemphasis) and post_pro.cpp
|
||||
// (Post_Process). weightAi applies gamma bandwidth expansion to an LP filter;
|
||||
// preemphasis is the 1st-order y[n]=x[n]-g·x[n-1]; postProcess is the decoder's
|
||||
// output high-pass biquad with the ×2 output scaling. Bit-exact with the
|
||||
// reference.
|
||||
|
||||
// weightAi computes the bandwidth-expanded coefficients a_exp[i] = a[i]·fac[i-1]
|
||||
// (with a_exp[0]=a[0]). Mirrors Weight_Ai.
|
||||
func weightAi(a []int16, fac []int16, aExp []int16) {
|
||||
aExp[0] = a[0]
|
||||
for i := 1; i <= cM; i++ {
|
||||
aExp[i] = int16((int32(a[i])*int32(fac[i-1]) + 0x4000) >> 15)
|
||||
}
|
||||
}
|
||||
|
||||
// preemphasis applies y[n] = x[n] - g·x[n-1] in place over L samples, carrying
|
||||
// one sample of memory. Mirrors preemphasis (preemph.cpp).
|
||||
func preemphasis(memPre *int16, signal []int16, g int16, L int) {
|
||||
temp := signal[L-1]
|
||||
for i := L - 1; i >= 1; i-- {
|
||||
signal[i] = sub(signal[i], mult(g, signal[i-1]))
|
||||
}
|
||||
signal[0] = sub(signal[0], mult(g, *memPre))
|
||||
*memPre = temp
|
||||
}
|
||||
|
||||
// post-process output high-pass biquad coefficients (post_pro.cpp).
|
||||
var postB = [3]int16{7699, -15398, 7699}
|
||||
var postA = [3]int16{8192, 15836, -7667}
|
||||
|
||||
// postProcessState holds the biquad's double-precision input/output memory.
|
||||
type postProcessState struct {
|
||||
x0, x1 int16
|
||||
y1hi, y1lo, y2hi, y2lo int16
|
||||
}
|
||||
|
||||
// process applies the output high-pass filter (with ×2 gain) in place over lg
|
||||
// samples. The feedback memory is kept as (hi,lo) double precision. Mirrors
|
||||
// Post_Process.
|
||||
func (st *postProcessState) process(signal []int16, lg int) {
|
||||
a1, a2 := int32(postA[1]), int32(postA[2])
|
||||
b0, b1, b2 := int32(postB[0]), int32(postB[1]), int32(postB[2])
|
||||
for i := 0; i < lg; i++ {
|
||||
x2 := st.x1
|
||||
st.x1 = st.x0
|
||||
st.x0 = signal[i]
|
||||
|
||||
L := int32(st.y1hi) * a1
|
||||
L += (int32(st.y1lo) * a1) >> 15
|
||||
L += int32(st.y2hi) * a2
|
||||
L += (int32(st.y2lo) * a2) >> 15
|
||||
L += int32(st.x0) * b0
|
||||
L += int32(st.x1) * b1
|
||||
L += int32(x2) * b2
|
||||
|
||||
L = L_shl(L, 3)
|
||||
signal[i] = round_(L_shl(L, 1))
|
||||
|
||||
st.y2hi = st.y1hi
|
||||
st.y2lo = st.y1lo
|
||||
st.y1hi = int16(L >> 16)
|
||||
st.y1lo = int16((L >> 1) - (int32(st.y1hi) << 15))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package amrnb
|
||||
|
||||
// Adaptive formant post-filter, ported from opencore-amrnb pstfilt.cpp. For each
|
||||
// subframe it builds the weighted LP filters A(z/γ3) and A(z/γ4), forms the
|
||||
// residual through A(z/γ3), derives a spectral-tilt compensation coefficient
|
||||
// from the truncated impulse response, applies it via preemphasis, synthesizes
|
||||
// through 1/A(z/γ4), and finally matches the energy back to the synthesis with
|
||||
// AGC. Uses the building blocks weightAi/residu/synFilt/preemphasis/agc; this is
|
||||
// the orchestration that chains them. Bit-exact with the reference.
|
||||
|
||||
const (
|
||||
cL_H = 22 // truncated impulse-response length
|
||||
cMU = 26214 // tilt compensation factor (0.8)
|
||||
)
|
||||
|
||||
// γ bandwidth-expansion factors (pstfilt.cpp).
|
||||
var gamma3MR122 = [cM]int16{22938, 16057, 11240, 7868, 5508, 3856, 2699, 1889, 1322, 925}
|
||||
var gamma3 = [cM]int16{18022, 9912, 5451, 2998, 1649, 907, 499, 274, 151, 83}
|
||||
var gamma4MR122 = [cM]int16{24576, 18432, 13824, 10368, 7776, 5832, 4374, 3281, 2461, 1846}
|
||||
var gamma4 = [cM]int16{22938, 16057, 11240, 7868, 5508, 3856, 2699, 1889, 1322, 925}
|
||||
|
||||
// postFilterState holds the formant post-filter memory across frames.
|
||||
type postFilterState struct {
|
||||
res2 [cL_SUBFR]int16
|
||||
memSynPst [cM]int16
|
||||
preemph int16
|
||||
agc agcState
|
||||
synthBuf [cM + cL_FRAME]int16 // M history + current frame
|
||||
}
|
||||
|
||||
func (st *postFilterState) reset() {
|
||||
*st = postFilterState{}
|
||||
}
|
||||
|
||||
// postFilter post-filters one 160-sample synthesis frame in place. az4 holds the
|
||||
// four per-subframe LP coefficient sets (4*cMP1). Mirrors Post_Filter.
|
||||
func (st *postFilterState) postFilter(mode int, syn []int16, az4 []int16) {
|
||||
var ap3, ap4 [cMP1]int16
|
||||
var h [cL_H]int16
|
||||
|
||||
synWork := st.synthBuf[cM:] // syn_work[i] == synthBuf[M+i]
|
||||
copy(synWork[:cL_FRAME], syn[:cL_FRAME])
|
||||
|
||||
azOff := 0
|
||||
for iSubfr := 0; iSubfr < cL_FRAME; iSubfr += cL_SUBFR {
|
||||
az := az4[azOff:]
|
||||
if mode == dMR122 || mode == dMR102 {
|
||||
weightAi(az, gamma3MR122[:], ap3[:])
|
||||
weightAi(az, gamma4MR122[:], ap4[:])
|
||||
} else {
|
||||
weightAi(az, gamma3[:], ap3[:])
|
||||
weightAi(az, gamma4[:], ap4[:])
|
||||
}
|
||||
|
||||
// Residual through A(z/γ3); syn_work[iSubfr] == synthBuf[M+iSubfr].
|
||||
residu(ap3[:], st.synthBuf[:], cM+iSubfr, cL_SUBFR, st.res2[:])
|
||||
|
||||
// Truncated impulse response of A(z/γ3)/A(z/γ4).
|
||||
copy(h[:cMP1], ap3[:cMP1])
|
||||
for i := cMP1; i < cL_H; i++ {
|
||||
h[i] = 0
|
||||
}
|
||||
synFilt(ap4[:], h[:], h[:], cL_H, h[cMP1:], false)
|
||||
|
||||
// Tilt compensation coefficient from the impulse-response autocorr.
|
||||
var lTmp int32
|
||||
for i := cL_H - 1; i >= 0; i-- {
|
||||
t2 := int32(h[i]) * int32(h[i])
|
||||
if t2 == 0x40000000 {
|
||||
break // reference sets overflow and stops without adding
|
||||
}
|
||||
lTmp = L_add(lTmp, t2<<1)
|
||||
}
|
||||
temp1 := int16(lTmp >> 16)
|
||||
|
||||
lTmp = 0
|
||||
for i := cL_H - 2; i >= 0; i-- {
|
||||
t2 := int32(h[i]) * int32(h[i+1])
|
||||
if t2 == 0x40000000 {
|
||||
break
|
||||
}
|
||||
lTmp = L_add(lTmp, t2<<1)
|
||||
}
|
||||
temp2 := int16(lTmp >> 16)
|
||||
|
||||
if temp2 <= 0 {
|
||||
temp2 = 0
|
||||
} else {
|
||||
lt := (int32(temp2) * cMU) >> 15
|
||||
if lt&0x00010000 != 0 {
|
||||
lt |= int32(-0x10000)
|
||||
}
|
||||
temp2 = int16(lt)
|
||||
temp2 = div_s(temp2, temp1)
|
||||
}
|
||||
|
||||
preemphasis(&st.preemph, st.res2[:], temp2, cL_SUBFR)
|
||||
|
||||
synFilt(ap4[:], st.res2[:], syn[iSubfr:], cL_SUBFR, st.memSynPst[:], true)
|
||||
|
||||
st.agc.agc(synWork[iSubfr:], syn[iSubfr:], cAGC_FAC, cL_SUBFR)
|
||||
|
||||
azOff += cMP1
|
||||
}
|
||||
|
||||
// Carry the last M samples as history for the next frame.
|
||||
copy(st.synthBuf[:cM], synWork[cL_FRAME-cM:cL_FRAME])
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package amrnb
|
||||
|
||||
// LP synthesis and analysis filters, ported from opencore-amrnb syn_filt.cpp
|
||||
// and residu.cpp (order 10). synFilt runs the all-pole synthesis 1/A(z) over a
|
||||
// subframe, carrying M samples of filter memory; residu runs the all-zero
|
||||
// analysis A(z). Both accumulate products in wrapping int32 (the reference's
|
||||
// non-saturating MAC/MSU), so a straightforward per-output loop is bit-exact;
|
||||
// synFilt's output clamp reproduces the reference's exact boundary behaviour.
|
||||
|
||||
// synClamp reproduces the Syn_filt overflow clamp: in-range values are an
|
||||
// arithmetic >>12, out-of-range saturate to ±MAX_16. The asymmetric boundary
|
||||
// (s == 0x07ffffff -> MIN_16) is a reference quirk preserved deliberately.
|
||||
func synClamp(s int32) int16 {
|
||||
if uint32(s+134217728) < 0x0fffffff {
|
||||
return int16(s >> 12)
|
||||
} else if s > 0x07ffffff {
|
||||
return maxInt16
|
||||
}
|
||||
return minInt16
|
||||
}
|
||||
|
||||
// synFilt computes y = x convolved with 1/A(z) over lg samples, where a[0:M+1]
|
||||
// are the LP coefficients (a[0]=4096, Q12). mem[0:M] holds the M past output
|
||||
// samples; if update is true it is refreshed with the last M outputs. Mirrors
|
||||
// Syn_filt.
|
||||
func synFilt(a, x, y []int16, lg int, mem []int16, update bool) {
|
||||
var yy [cL_FRAME + cM]int16
|
||||
copy(yy[:cM], mem[:cM])
|
||||
|
||||
af := a[:cMP1] // hoist bounds: a[0..M]
|
||||
xf := x[:lg]
|
||||
for i := 0; i < lg; i++ {
|
||||
s := int32(0x800) + int32(af[0])*int32(xf[i])
|
||||
yw := yy[i : i+cM] // yy[cM+i-j] == yw[cM-j], all in [0,cM)
|
||||
s -= int32(af[1]) * int32(yw[cM-1])
|
||||
s -= int32(af[2]) * int32(yw[cM-2])
|
||||
s -= int32(af[3]) * int32(yw[cM-3])
|
||||
s -= int32(af[4]) * int32(yw[cM-4])
|
||||
s -= int32(af[5]) * int32(yw[cM-5])
|
||||
s -= int32(af[6]) * int32(yw[cM-6])
|
||||
s -= int32(af[7]) * int32(yw[cM-7])
|
||||
s -= int32(af[8]) * int32(yw[cM-8])
|
||||
s -= int32(af[9]) * int32(yw[cM-9])
|
||||
s -= int32(af[10]) * int32(yw[cM-10])
|
||||
out := synClamp(s)
|
||||
yy[cM+i] = out
|
||||
y[i] = out
|
||||
}
|
||||
|
||||
if update {
|
||||
copy(mem[:cM], y[lg-cM:lg])
|
||||
}
|
||||
}
|
||||
|
||||
// residu computes the LP residual A(z)·input over inputLen samples. buf holds
|
||||
// the input with at least M samples of history before start (buf[start-M:start]
|
||||
// are the past samples). Output goes to residual[0:inputLen]. Output is
|
||||
// truncated (not saturated) to 16 bits, matching the reference. Mirrors Residu.
|
||||
func residu(coef, buf []int16, start, inputLen int, residual []int16) {
|
||||
// res[i] = (0x800 + sum_{j=0..M} coef[j]·buf[start+i-j]) >> 12. Reversing the
|
||||
// coefficients turns the inner sum into a fixed-window FIR over buf[start-M:]
|
||||
// (res[i] = sum_k arev[k]·buf[start-M+i+k]), so it vectorises via firRaw. The
|
||||
// reference accumulates in plain wrapping int32, so the lane-parallel order is
|
||||
// bit-identical, and adding the 0x800 rounding bias after the sum is exact
|
||||
// (integer addition is associative mod 2^32).
|
||||
var arev [cMP1]int16
|
||||
for k := 0; k <= cM; k++ {
|
||||
arev[k] = coef[cM-k]
|
||||
}
|
||||
var dstArr [cL_SUBFR]int32
|
||||
var dst []int32
|
||||
if inputLen <= cL_SUBFR {
|
||||
dst = dstArr[:inputLen]
|
||||
} else {
|
||||
dst = make([]int32, inputLen)
|
||||
}
|
||||
firRaw(dst, buf[start-cM:], arev[:])
|
||||
for i := 0; i < inputLen; i++ {
|
||||
residual[i] = int16((0x800 + dst[i]) >> 12)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
// Package amrnb implements the AMR-NB (3GPP TS 26.071 / 26.090) narrowband
|
||||
// speech codec in pure Go, with RFC 4867 RTP payload framing.
|
||||
//
|
||||
// AMR-NB operates on 8 kHz mono audio in 20 ms frames (160 samples). It defines
|
||||
// eight speech coding modes (0..7) spanning 4.75 to 12.2 kbit/s, plus a comfort
|
||||
// noise (SID) frame used by DTX.
|
||||
package amrnb
|
||||
|
||||
// SampleRate is the fixed AMR-NB sampling rate in Hz.
|
||||
const SampleRate = 8000
|
||||
|
||||
// FrameSamples is the number of PCM samples in one 20 ms AMR-NB frame.
|
||||
const FrameSamples = 160
|
||||
|
||||
// Mode identifies an AMR-NB speech coding mode (0..7).
|
||||
type Mode int
|
||||
|
||||
const (
|
||||
Mode0475 Mode = iota // 4.75 kbit/s
|
||||
Mode0515 // 5.15 kbit/s
|
||||
Mode0590 // 5.90 kbit/s
|
||||
Mode0670 // 6.70 kbit/s
|
||||
Mode0740 // 7.40 kbit/s
|
||||
Mode0795 // 7.95 kbit/s
|
||||
Mode1020 // 10.2 kbit/s
|
||||
Mode1220 // 12.2 kbit/s
|
||||
numSpeechModes
|
||||
)
|
||||
|
||||
// Frame type (FT) values carried in the RFC 4867 ToC byte. Values 0..7 are the
|
||||
// speech modes; the remainder describe comfort noise and no-data frames. Note
|
||||
// that AMR-NB places SID at FT 8 (AMR-WB uses FT 9).
|
||||
const (
|
||||
FTMode0475 = 0
|
||||
FTMode0515 = 1
|
||||
FTMode0590 = 2
|
||||
FTMode0670 = 3
|
||||
FTMode0740 = 4
|
||||
FTMode0795 = 5
|
||||
FTMode1020 = 6
|
||||
FTMode1220 = 7
|
||||
FTSID = 8 // comfort noise (SID)
|
||||
FTSpeechLost = 14 // speech lost (RFC 4867)
|
||||
FTNoData = 15 // no data
|
||||
)
|
||||
|
||||
// modeBits is the number of speech bits per AMR-NB mode (0..7). These are the
|
||||
// canonical bit counts from 3GPP TS 26.101 (and RFC 4867 Table 1a).
|
||||
var modeBits = [numSpeechModes]int{
|
||||
95, // 4.75
|
||||
103, // 5.15
|
||||
118, // 5.90
|
||||
134, // 6.70
|
||||
148, // 7.40
|
||||
159, // 7.95
|
||||
204, // 10.2
|
||||
244, // 12.2
|
||||
}
|
||||
|
||||
// sidBits is the number of bits in an AMR-NB SID (comfort noise) frame.
|
||||
const sidBits = 39
|
||||
|
||||
// frameBitsByFT returns the number of payload bits for a given frame type and
|
||||
// whether the frame type is a recognized one that carries bits. SID and speech
|
||||
// modes carry bits; SPEECH_LOST and NO_DATA carry none.
|
||||
func frameBitsByFT(ft int) (bits int, ok bool) {
|
||||
switch {
|
||||
case ft >= FTMode0475 && ft <= FTMode1220:
|
||||
return modeBits[ft], true
|
||||
case ft == FTSID:
|
||||
return sidBits, true
|
||||
case ft == FTSpeechLost, ft == FTNoData:
|
||||
return 0, true
|
||||
default:
|
||||
return 0, false
|
||||
}
|
||||
}
|
||||
|
||||
// frameBytesByFT returns the number of octet-aligned bytes occupied by a frame
|
||||
// of the given type (bits rounded up to whole octets).
|
||||
func frameBytesByFT(ft int) (bytes int, ok bool) {
|
||||
bits, ok := frameBitsByFT(ft)
|
||||
if !ok {
|
||||
return 0, false
|
||||
}
|
||||
return (bits + 7) / 8, true
|
||||
}
|
||||
|
||||
// Bits returns the number of speech bits produced by this mode.
|
||||
func (m Mode) Bits() int {
|
||||
if m < 0 || m >= numSpeechModes {
|
||||
return 0
|
||||
}
|
||||
return modeBits[m]
|
||||
}
|
||||
|
||||
// Bytes returns the octet-aligned byte count of a frame in this mode.
|
||||
func (m Mode) Bytes() int { return (m.Bits() + 7) / 8 }
|
||||
|
||||
// FrameType returns the RFC 4867 frame-type value for this mode.
|
||||
func (m Mode) FrameType() int { return int(m) }
|
||||
|
||||
// Valid reports whether m is a defined speech mode.
|
||||
func (m Mode) Valid() bool { return m >= Mode0475 && m < numSpeechModes }
|
||||
|
||||
// Bitrate returns the nominal bit rate of the mode in bit/s.
|
||||
func (m Mode) Bitrate() int {
|
||||
switch m {
|
||||
case Mode0475:
|
||||
return 4750
|
||||
case Mode0515:
|
||||
return 5150
|
||||
case Mode0590:
|
||||
return 5900
|
||||
case Mode0670:
|
||||
return 6700
|
||||
case Mode0740:
|
||||
return 7400
|
||||
case Mode0795:
|
||||
return 7950
|
||||
case Mode1020:
|
||||
return 10200
|
||||
case Mode1220:
|
||||
return 12200
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
package amrnb
|
||||
|
||||
import "errors"
|
||||
|
||||
// RFC 4867 RTP payload framing for AMR-NB. Two formats are supported:
|
||||
//
|
||||
// - octet-aligned (octet-align=1): every field starts on an octet boundary.
|
||||
// Layout: [CMR(1 byte)] [ToC byte per frame] [speech bytes per frame].
|
||||
// - bandwidth-efficient: fields are bit-packed with no padding.
|
||||
// Layout: CMR(4 bits) then, per frame, ToC(6 bits) then the speech bits.
|
||||
//
|
||||
// Only the fields VoiceBlender needs are modelled. Interleaving and the
|
||||
// CRC/robust-sorting options are not used (they are negotiated off by default
|
||||
// and we never offer them).
|
||||
|
||||
// noCMR is the "no mode request" CMR value (15) emitted when we have no
|
||||
// preference to signal to the peer.
|
||||
const noCMR = 15
|
||||
|
||||
// frame is one decoded ToC entry plus its raw speech bits.
|
||||
type frame struct {
|
||||
ft int // frame type (FT)
|
||||
q bool // quality bit (Q): true = good frame
|
||||
data []byte // speech bits, octet-aligned, left-justified in the final byte
|
||||
}
|
||||
|
||||
var (
|
||||
errShortPayload = errors.New("amrnb: payload too short")
|
||||
errBadFrameType = errors.New("amrnb: unknown frame type")
|
||||
)
|
||||
|
||||
// packPayloadOctet builds an octet-aligned payload carrying the given frames
|
||||
// with the supplied CMR (use noCMR for none).
|
||||
func packPayloadOctet(cmr int, frames []frame) []byte {
|
||||
out := []byte{byte(cmr&0x0F) << 4}
|
||||
for i, f := range frames {
|
||||
last := i == len(frames)-1
|
||||
toc := byte(f.ft&0x0F) << 3
|
||||
if !last {
|
||||
toc |= 0x80 // F bit: more frames follow
|
||||
}
|
||||
if f.q {
|
||||
toc |= 0x04 // Q bit
|
||||
}
|
||||
out = append(out, toc)
|
||||
}
|
||||
for _, f := range frames {
|
||||
nb, _ := frameBytesByFT(f.ft)
|
||||
buf := make([]byte, nb)
|
||||
copy(buf, f.data)
|
||||
out = append(out, buf...)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// unpackPayloadOctet parses an octet-aligned payload into its frames and CMR.
|
||||
func unpackPayloadOctet(p []byte) (cmr int, frames []frame, err error) {
|
||||
if len(p) < 1 {
|
||||
return 0, nil, errShortPayload
|
||||
}
|
||||
cmr = int(p[0] >> 4)
|
||||
idx := 1
|
||||
// Read ToC bytes until the F bit clears.
|
||||
var tocs []byte
|
||||
for {
|
||||
if idx >= len(p) {
|
||||
return 0, nil, errShortPayload
|
||||
}
|
||||
toc := p[idx]
|
||||
idx++
|
||||
tocs = append(tocs, toc)
|
||||
if toc&0x80 == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
for _, toc := range tocs {
|
||||
ft := int(toc>>3) & 0x0F
|
||||
q := toc&0x04 != 0
|
||||
nb, ok := frameBytesByFT(ft)
|
||||
if !ok {
|
||||
return 0, nil, errBadFrameType
|
||||
}
|
||||
if idx+nb > len(p) {
|
||||
return 0, nil, errShortPayload
|
||||
}
|
||||
data := make([]byte, nb)
|
||||
copy(data, p[idx:idx+nb])
|
||||
idx += nb
|
||||
frames = append(frames, frame{ft: ft, q: q, data: data})
|
||||
}
|
||||
return cmr, frames, nil
|
||||
}
|
||||
|
||||
// packPayloadBandwidthEfficient builds a bandwidth-efficient payload.
|
||||
func packPayloadBandwidthEfficient(cmr int, frames []frame) []byte {
|
||||
w := &bitWriter{}
|
||||
w.writeBits(uint32(cmr&0x0F), 4)
|
||||
for i, f := range frames {
|
||||
last := i == len(frames)-1
|
||||
fBit := uint32(0)
|
||||
if !last {
|
||||
fBit = 1
|
||||
}
|
||||
w.writeBits(fBit, 1)
|
||||
w.writeBits(uint32(f.ft&0x0F), 4)
|
||||
q := uint32(0)
|
||||
if f.q {
|
||||
q = 1
|
||||
}
|
||||
w.writeBits(q, 1)
|
||||
}
|
||||
for _, f := range frames {
|
||||
bits, _ := frameBitsByFT(f.ft)
|
||||
w.writeBitsFromBytes(f.data, bits)
|
||||
}
|
||||
return w.bytes()
|
||||
}
|
||||
|
||||
// unpackPayloadBandwidthEfficient parses a bandwidth-efficient payload.
|
||||
func unpackPayloadBandwidthEfficient(p []byte) (cmr int, frames []frame, err error) {
|
||||
r := &bitReader{data: p}
|
||||
c, ok := r.readBits(4)
|
||||
if !ok {
|
||||
return 0, nil, errShortPayload
|
||||
}
|
||||
cmr = int(c)
|
||||
type toc struct {
|
||||
ft int
|
||||
q bool
|
||||
}
|
||||
var tocs []toc
|
||||
for {
|
||||
fBit, ok := r.readBits(1)
|
||||
if !ok {
|
||||
return 0, nil, errShortPayload
|
||||
}
|
||||
ft, ok := r.readBits(4)
|
||||
if !ok {
|
||||
return 0, nil, errShortPayload
|
||||
}
|
||||
qBit, ok := r.readBits(1)
|
||||
if !ok {
|
||||
return 0, nil, errShortPayload
|
||||
}
|
||||
if _, valid := frameBitsByFT(int(ft)); !valid {
|
||||
return 0, nil, errBadFrameType
|
||||
}
|
||||
tocs = append(tocs, toc{ft: int(ft), q: qBit == 1})
|
||||
if fBit == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
for _, t := range tocs {
|
||||
bits, _ := frameBitsByFT(t.ft)
|
||||
data, ok := r.readBitsToBytes(bits)
|
||||
if !ok {
|
||||
return 0, nil, errShortPayload
|
||||
}
|
||||
frames = append(frames, frame{ft: t.ft, q: t.q, data: data})
|
||||
}
|
||||
return cmr, frames, nil
|
||||
}
|
||||
|
||||
// bitWriter accumulates bits MSB-first into a byte slice.
|
||||
type bitWriter struct {
|
||||
buf []byte
|
||||
cur byte
|
||||
nimb int // number of bits filled in cur
|
||||
}
|
||||
|
||||
func (w *bitWriter) writeBit(b uint32) {
|
||||
w.cur |= byte(b&1) << uint(7-w.nimb)
|
||||
w.nimb++
|
||||
if w.nimb == 8 {
|
||||
w.buf = append(w.buf, w.cur)
|
||||
w.cur = 0
|
||||
w.nimb = 0
|
||||
}
|
||||
}
|
||||
|
||||
func (w *bitWriter) writeBits(v uint32, n int) {
|
||||
for i := n - 1; i >= 0; i-- {
|
||||
w.writeBit(v >> uint(i))
|
||||
}
|
||||
}
|
||||
|
||||
// writeBitsFromBytes writes the first n bits of data, MSB-first.
|
||||
func (w *bitWriter) writeBitsFromBytes(data []byte, n int) {
|
||||
for i := 0; i < n; i++ {
|
||||
bit := uint32(0)
|
||||
if byteIdx := i / 8; byteIdx < len(data) {
|
||||
bit = uint32(data[byteIdx]>>uint(7-i%8)) & 1
|
||||
}
|
||||
w.writeBit(bit)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *bitWriter) bytes() []byte {
|
||||
out := w.buf
|
||||
if w.nimb > 0 {
|
||||
out = append(out, w.cur)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// bitReader reads bits MSB-first from a byte slice.
|
||||
type bitReader struct {
|
||||
data []byte
|
||||
pos int // bit position
|
||||
}
|
||||
|
||||
func (r *bitReader) readBits(n int) (uint32, bool) {
|
||||
var v uint32
|
||||
for i := 0; i < n; i++ {
|
||||
if r.pos >= len(r.data)*8 {
|
||||
return 0, false
|
||||
}
|
||||
bit := uint32(r.data[r.pos/8]>>uint(7-r.pos%8)) & 1
|
||||
v = (v << 1) | bit
|
||||
r.pos++
|
||||
}
|
||||
return v, true
|
||||
}
|
||||
|
||||
// readBitsToBytes reads n bits and returns them left-justified in a byte slice.
|
||||
func (r *bitReader) readBitsToBytes(n int) ([]byte, bool) {
|
||||
out := make([]byte, (n+7)/8)
|
||||
for i := 0; i < n; i++ {
|
||||
if r.pos >= len(r.data)*8 {
|
||||
return nil, false
|
||||
}
|
||||
bit := r.data[r.pos/8] >> uint(7-r.pos%8) & 1
|
||||
out[i/8] |= bit << uint(7-i%8)
|
||||
r.pos++
|
||||
}
|
||||
return out, true
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package amrnb
|
||||
|
||||
// SIMD-accelerated non-saturating int16 FIR, used by the hot filter kernels.
|
||||
// The reference accumulates products into a plain int32 (no per-term
|
||||
// saturation), and integer addition is associative modulo 2^32, so accumulating
|
||||
// in the lane-parallel order an AVX2 kernel uses yields a bit-identical result.
|
||||
// firRawGeneric is the portable fallback and the oracle the assembly is
|
||||
// fuzz-tested against.
|
||||
|
||||
// firRawGeneric computes the raw (pre-round, pre-shift) FIR sums
|
||||
// dst[o] = sum_t x[o+t]*coef[t] for every output o, accumulating in wrapping
|
||||
// int32. The amd64 build vectorises this across 8 outputs at a time; this is
|
||||
// the portable fallback and the fuzz-test oracle. Requires
|
||||
// len(x) >= len(dst)+len(coef)-1.
|
||||
func firRawGeneric(dst []int32, x []int16, coef []int16) {
|
||||
taps := len(coef)
|
||||
for o := range dst {
|
||||
xw := x[o : o+taps]
|
||||
var s int32
|
||||
for t, c := range coef {
|
||||
s += int32(xw[t]) * int32(c)
|
||||
}
|
||||
dst[o] = s
|
||||
}
|
||||
}
|
||||
|
||||
// firDotGeneric computes the wrapping-int32 dot product sum_i a[i]*b[i] over the
|
||||
// first len(a) elements (requires len(b) >= len(a)). The amd64 build vectorises
|
||||
// it with VPMADDWD; this is the portable fallback and the fuzz-test oracle.
|
||||
func firDotGeneric(a, b []int16) int32 {
|
||||
bb := b[:len(a)]
|
||||
var s int32
|
||||
for i, av := range a {
|
||||
s += int32(av) * int32(bb[i])
|
||||
}
|
||||
return s
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
//go:build amd64
|
||||
|
||||
package amrnb
|
||||
|
||||
import "golang.org/x/sys/cpu"
|
||||
|
||||
var useAVX2 = cpu.X86.HasAVX2
|
||||
|
||||
// firRaw computes dst[o] = sum_t x[o+t]*coef[t] (wrapping int32). On AVX2 it
|
||||
// vectorises across 8 outputs per iteration; otherwise it falls back.
|
||||
func firRaw(dst []int32, x []int16, coef []int16) {
|
||||
if useAVX2 && len(dst) >= 8 && len(coef) <= maxFIRTaps {
|
||||
var c32 [maxFIRTaps]int32
|
||||
for i, c := range coef {
|
||||
c32[i] = int32(c)
|
||||
}
|
||||
firRawAVX2(dst, x, c32[:len(coef)])
|
||||
return
|
||||
}
|
||||
firRawGeneric(dst, x, coef)
|
||||
}
|
||||
|
||||
// maxFIRTaps bounds the stack-resident sign-extended coefficient buffer. It
|
||||
// covers the longest FIR used: the open-loop pitch correlation window, which
|
||||
// spans a whole frame (L_FRAME = 160 taps).
|
||||
const maxFIRTaps = 256
|
||||
|
||||
// firRawAVX2 is implemented in simd_amd64.s. coef32 holds sign-extended taps.
|
||||
//
|
||||
//go:noescape
|
||||
func firRawAVX2(dst []int32, x []int16, coef32 []int32)
|
||||
|
||||
// firDot computes the wrapping-int32 dot product sum_i a[i]*b[i] over len(a)
|
||||
// elements. On AVX2 it uses VPMADDWD across 16 int16 per iteration; otherwise it
|
||||
// falls back.
|
||||
func firDot(a, b []int16) int32 {
|
||||
if useAVX2 && len(a) >= 16 {
|
||||
return firDotAVX2(a, b)
|
||||
}
|
||||
return firDotGeneric(a, b)
|
||||
}
|
||||
|
||||
// firDotAVX2 is implemented in simd_amd64.s. It reads len(a) int16 from a and b.
|
||||
//
|
||||
//go:noescape
|
||||
func firDotAVX2(a, b []int16) int32
|
||||
@@ -0,0 +1,121 @@
|
||||
//go:build amd64
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// func firRawAVX2(dst []int32, x []int16, coef32 []int32)
|
||||
// dst[o] = sum_t x[o+t]*coef32[t], vectorised across 8 outputs per iteration:
|
||||
// lane k accumulates output og+k, so no per-output horizontal reduction.
|
||||
TEXT ·firRawAVX2(SB), NOSPLIT, $0-72
|
||||
MOVQ dst_base+0(FP), DI
|
||||
MOVQ dst_len+8(FP), CX // number of outputs
|
||||
MOVQ x_base+24(FP), SI // &x[og] (group base)
|
||||
MOVQ coef32_base+48(FP), BX
|
||||
MOVQ coef32_len+56(FP), R9 // taps
|
||||
|
||||
MOVQ CX, R10
|
||||
SHRQ $3, R10 // R10 = groups of 8 outputs
|
||||
JZ firtail
|
||||
|
||||
grouploop:
|
||||
VPXOR Y0, Y0, Y0
|
||||
MOVQ SI, R11 // x cursor for this group
|
||||
MOVQ BX, R12 // coef cursor
|
||||
MOVQ R9, R13 // tap counter
|
||||
|
||||
taploop:
|
||||
VPMOVSXWD (R11), Y1 // 8 int16 x[og+t..og+t+7] -> 8 int32
|
||||
VPBROADCASTD (R12), Y2 // coef32[t] in all 8 lanes
|
||||
VPMULLD Y2, Y1, Y3
|
||||
VPADDD Y3, Y0, Y0
|
||||
ADDQ $2, R11 // next tap shifts x window by 1 int16
|
||||
ADDQ $4, R12
|
||||
DECQ R13
|
||||
JNZ taploop
|
||||
|
||||
VMOVDQU Y0, (DI)
|
||||
ADDQ $32, DI // 8 int32 stored
|
||||
ADDQ $16, SI // next group: x base += 8 int16
|
||||
DECQ R10
|
||||
JNZ grouploop
|
||||
|
||||
firtail:
|
||||
ANDQ $7, CX // remaining outputs (<8)
|
||||
JZ firdone
|
||||
|
||||
tailout:
|
||||
MOVQ SI, R11
|
||||
MOVQ BX, R12
|
||||
MOVQ R9, R13
|
||||
XORL AX, AX
|
||||
|
||||
tailtap:
|
||||
MOVWLSX (R11), DX
|
||||
MOVL (R12), R8
|
||||
IMULL R8, DX
|
||||
ADDL DX, AX
|
||||
ADDQ $2, R11
|
||||
ADDQ $4, R12
|
||||
DECQ R13
|
||||
JNZ tailtap
|
||||
|
||||
MOVL AX, (DI)
|
||||
ADDQ $4, DI
|
||||
ADDQ $2, SI // next single output: x base += 1 int16
|
||||
DECQ CX
|
||||
JNZ tailout
|
||||
|
||||
firdone:
|
||||
VZEROUPPER
|
||||
RET
|
||||
|
||||
// func firDotAVX2(a, b []int16) int32
|
||||
// Returns sum_i a[i]*b[i] (wrapping int32) over len(a) elements. VPMADDWD folds
|
||||
// each int16 pair into an int32 (exact mod 2^32); lanes accumulate, then a
|
||||
// horizontal sum + scalar tail. All adds wrap, so the order matches the scalar.
|
||||
TEXT ·firDotAVX2(SB), NOSPLIT, $0-52
|
||||
MOVQ a_base+0(FP), SI
|
||||
MOVQ a_len+8(FP), CX
|
||||
MOVQ b_base+24(FP), DI
|
||||
VPXOR Y0, Y0, Y0 // accumulator: 8 int32 lanes
|
||||
|
||||
MOVQ CX, R10
|
||||
SHRQ $4, R10 // groups of 16 int16
|
||||
JZ dtail
|
||||
|
||||
dloop:
|
||||
VMOVDQU (SI), Y1 // 16 int16 a
|
||||
VMOVDQU (DI), Y2 // 16 int16 b
|
||||
VPMADDWD Y2, Y1, Y3 // 8 int32: a[2k]*b[2k] + a[2k+1]*b[2k+1]
|
||||
VPADDD Y3, Y0, Y0
|
||||
ADDQ $32, SI
|
||||
ADDQ $32, DI
|
||||
DECQ R10
|
||||
JNZ dloop
|
||||
|
||||
dtail:
|
||||
// horizontal sum of the 8 int32 lanes -> AX
|
||||
VEXTRACTI128 $1, Y0, X1
|
||||
VPADDD X1, X0, X0 // 4 int32
|
||||
VPSHUFD $0x4E, X0, X1 // [2,3,0,1]
|
||||
VPADDD X1, X0, X0 // 2 int32
|
||||
VPSHUFD $0xB1, X0, X1 // [1,0,3,2]
|
||||
VPADDD X1, X0, X0 // 1 int32
|
||||
MOVD X0, AX
|
||||
|
||||
ANDQ $15, CX // remaining elements (<16)
|
||||
JZ ddone
|
||||
|
||||
dscalar:
|
||||
MOVWLSX (SI), DX
|
||||
MOVWLSX (DI), R8
|
||||
IMULL R8, DX
|
||||
ADDL DX, AX
|
||||
ADDQ $2, SI
|
||||
ADDQ $2, DI
|
||||
DECQ CX
|
||||
JNZ dscalar
|
||||
|
||||
ddone:
|
||||
VZEROUPPER
|
||||
MOVL AX, ret+48(FP)
|
||||
RET
|
||||
@@ -0,0 +1,9 @@
|
||||
//go:build !amd64
|
||||
|
||||
package amrnb
|
||||
|
||||
// firRaw falls back to the portable implementation on non-amd64 targets.
|
||||
func firRaw(dst []int32, x []int16, coef []int16) { firRawGeneric(dst, x, coef) }
|
||||
|
||||
// firDot falls back to the portable implementation on non-amd64 targets.
|
||||
func firDot(a, b []int16) int32 { return firDotGeneric(a, b) }
|
||||
@@ -0,0 +1,62 @@
|
||||
// Code generated from opencore-amrnb — DO NOT EDIT.
|
||||
//
|
||||
// ROM tables extracted verbatim from the Apache-2.0 opencore-amrnb C
|
||||
// reference; element counts are verified against the C array sizes.
|
||||
|
||||
package amrnb
|
||||
|
||||
var startPos = []int16{
|
||||
0, 2, 0, 3, 0, 2, 0, 3, 1, 3, 2, 4,
|
||||
1, 4, 1, 4,
|
||||
}
|
||||
|
||||
var gray = []int16{
|
||||
0, 1, 3, 2, 6, 4, 5, 7,
|
||||
}
|
||||
|
||||
var dgray = []int16{
|
||||
0, 1, 3, 2, 5, 6, 4, 7,
|
||||
}
|
||||
|
||||
var ph_imp_low_MR795 = []int16{
|
||||
26777, 801, 2505, -683, -1382, 582, 604, -1274, 3511, -5894, 4534, -499,
|
||||
-1940, 3011, -5058, 5614, -1990, -1061, -1459, 4442, -700, -5335, 4609, 452,
|
||||
-589, -3352, 2953, 1267, -1212, -2590, 1731, 3670, -4475, -975, 4391, -2537,
|
||||
949, -1363, -979, 5734,
|
||||
}
|
||||
|
||||
var ph_imp_mid_MR795 = []int16{
|
||||
30274, 3831, -4036, 2972, -1048, -1002, 2477, -3043, 2815, -2231, 1753, -1611,
|
||||
1714, -1775, 1543, -1008, 429, -169, 472, -1264, 2176, -2706, 2523, -1621,
|
||||
344, 826, -1529, 1724, -1657, 1701, -2063, 2644, -3060, 2897, -1978, 557,
|
||||
780, -1369, 842, 655,
|
||||
}
|
||||
|
||||
var ph_imp_low = []int16{
|
||||
14690, 11518, 1268, -2761, -5671, 7514, -35, -2807, -3040, 4823, 2952, -8424,
|
||||
3785, 1455, 2179, -8637, 8051, -2103, -1454, 777, 1108, -2385, 2254, -363,
|
||||
-674, -2103, 6046, -5681, 1072, 3123, -5058, 5312, -2329, -3728, 6924, -3889,
|
||||
675, -1775, 29, 10145,
|
||||
}
|
||||
|
||||
var ph_imp_mid = []int16{
|
||||
30274, 3831, -4036, 2972, -1048, -1002, 2477, -3043, 2815, -2231, 1753, -1611,
|
||||
1714, -1775, 1543, -1008, 429, -169, 472, -1264, 2176, -2706, 2523, -1621,
|
||||
344, 826, -1529, 1724, -1657, 1701, -2063, 2644, -3060, 2897, -1978, 557,
|
||||
780, -1369, 842, 655,
|
||||
}
|
||||
|
||||
// inter_6_pred_lt is the 1/6-resolution pitch interpolation FIR
|
||||
// (pred_lt.cpp), FIR_SIZE = L_INTER10*UP_SAMP_MAX+1 = 61.
|
||||
var inter_6_pred_lt = []int16{
|
||||
29443, 28346, 25207, 20449, 14701, 8693, 3143, -1352, -4402, -5865, -5850, -4673,
|
||||
-2783, -672, 1211, 2536, 3130, 2991, 2259, 1170, 0, -1001, -1652, -1868,
|
||||
-1666, -1147, -464, 218, 756, 1060, 1099, 904, 550, 135, -245, -514,
|
||||
-634, -602, -451, -231, 0, 191, 308, 340, 296, 198, 78, -36,
|
||||
-120, -163, -165, -132, -79, -19, 34, 73, 91, 89, 70, 38,
|
||||
0,
|
||||
}
|
||||
|
||||
// inter6Pitch: 1/6-resolution interpolation FIR for the closed-loop pitch
|
||||
// search (inter_36_tab.cpp), FIR_SIZE = UP_SAMP_MAX*L_INTER_SRCH+1 = 25.
|
||||
var inter6Pitch = []int16{29519, 28316, 24906, 19838, 13896, 7945, 2755, -1127, -3459, -4304, -3969, -2899, -1561, -336, 534, 970, 1023, 823, 516, 220, 0, -131, -194, -215, 0}
|
||||
@@ -0,0 +1,186 @@
|
||||
// Code generated from opencore-amrnb — DO NOT EDIT.
|
||||
//
|
||||
// ROM tables extracted verbatim from the Apache-2.0 opencore-amrnb C
|
||||
// reference; element counts are verified against the C array sizes.
|
||||
|
||||
package amrnb
|
||||
|
||||
var qua_gain_pitch = []int16{
|
||||
0, 3277, 6556, 8192, 9830, 11469, 12288, 13107, 13926, 14746, 15565, 16384,
|
||||
17203, 18022, 18842, 19661,
|
||||
}
|
||||
|
||||
var qua_gain_code = []int16{
|
||||
159, -3776, -22731, 206, -3394, -20428, 268, -3005, -18088, 349, -2615, -15739,
|
||||
419, -2345, -14113, 482, -2138, -12867, 554, -1932, -11629, 637, -1726, -10387,
|
||||
733, -1518, -9139, 842, -1314, -7906, 969, -1106, -6656, 1114, -900, -5416,
|
||||
1281, -694, -4173, 1473, -487, -2931, 1694, -281, -1688, 1948, -75, -445,
|
||||
2241, 133, 801, 2577, 339, 2044, 2963, 545, 3285, 3408, 752, 4530,
|
||||
3919, 958, 5772, 4507, 1165, 7016, 5183, 1371, 8259, 5960, 1577, 9501,
|
||||
6855, 1784, 10745, 7883, 1991, 11988, 9065, 2197, 13231, 10425, 2404, 14474,
|
||||
12510, 2673, 16096, 16263, 3060, 18429, 21142, 3448, 20763, 27485, 3836, 23097,
|
||||
27485, 3836, 23097,
|
||||
}
|
||||
|
||||
var table_gain_highrates = []int16{
|
||||
577, 662, -2692, -16214, 806, 1836, -1185, -7135, 3109, 1052, -2008, -12086,
|
||||
4181, 1387, -1600, -9629, 2373, 1425, -1560, -9394, 3248, 1985, -1070, -6442,
|
||||
1827, 2320, -840, -5056, 941, 3314, -313, -1885, 2351, 2977, -471, -2838,
|
||||
3616, 2420, -777, -4681, 3451, 3096, -414, -2490, 2955, 4301, 72, 434,
|
||||
1848, 4500, 139, 836, 3884, 5416, 413, 2484, 1187, 7210, 835, 5030,
|
||||
3083, 9000, 1163, 7002, 7384, 883, -2267, -13647, 5962, 1506, -1478, -8900,
|
||||
5155, 2134, -963, -5800, 7944, 2009, -1052, -6335, 6507, 2250, -885, -5327,
|
||||
7670, 2752, -588, -3537, 5952, 3016, -452, -2724, 4898, 3764, -125, -751,
|
||||
6989, 3588, -196, -1177, 8174, 3978, -43, -260, 6064, 4404, 107, 645,
|
||||
7709, 5087, 320, 1928, 5523, 6021, 569, 3426, 7769, 7126, 818, 4926,
|
||||
6060, 7938, 977, 5885, 5594, 11487, 1523, 9172, 10581, 1356, -1633, -9831,
|
||||
9049, 1597, -1391, -8380, 9794, 2035, -1033, -6220, 8946, 2415, -780, -4700,
|
||||
10296, 2584, -681, -4099, 9407, 2734, -597, -3595, 8700, 3218, -356, -2144,
|
||||
9757, 3395, -277, -1669, 10177, 3892, -75, -454, 9170, 4528, 148, 891,
|
||||
10152, 5004, 296, 1781, 9114, 5735, 497, 2993, 10500, 6266, 628, 3782,
|
||||
10110, 7631, 919, 5534, 8844, 8727, 1117, 6728, 8956, 12496, 1648, 9921,
|
||||
12924, 976, -2119, -12753, 11435, 1755, -1252, -7539, 12138, 2328, -835, -5024,
|
||||
11388, 2368, -810, -4872, 10700, 3064, -429, -2580, 12332, 2861, -530, -3192,
|
||||
11722, 3327, -307, -1848, 11270, 3700, -150, -904, 10861, 4413, 110, 663,
|
||||
12082, 4533, 150, 902, 11283, 5205, 354, 2132, 11960, 6305, 637, 3837,
|
||||
11167, 7534, 900, 5420, 12128, 8329, 1049, 6312, 10969, 10777, 1429, 8604,
|
||||
10300, 17376, 2135, 12853, 13899, 1681, -1316, -7921, 12580, 2045, -1026, -6179,
|
||||
13265, 2439, -766, -4610, 14033, 2989, -465, -2802, 13452, 3098, -413, -2482,
|
||||
12396, 3658, -167, -1006, 13510, 3780, -119, -713, 12880, 4272, 62, 374,
|
||||
13533, 4861, 253, 1523, 12667, 5457, 424, 2552, 13854, 6106, 590, 3551,
|
||||
13031, 6483, 678, 4084, 13557, 7721, 937, 5639, 12957, 9311, 1213, 7304,
|
||||
13714, 11551, 1532, 9221, 12591, 15206, 1938, 11667, 15113, 1540, -1445, -8700,
|
||||
15072, 2333, -832, -5007, 14527, 2511, -723, -4352, 14692, 3199, -365, -2197,
|
||||
15382, 3560, -207, -1247, 14133, 3960, -50, -300, 15102, 4236, 50, 298,
|
||||
14332, 4824, 242, 1454, 14846, 5451, 422, 2542, 15306, 6083, 584, 3518,
|
||||
14329, 6888, 768, 4623, 15060, 7689, 930, 5602, 14406, 9426, 1231, 7413,
|
||||
15387, 9741, 1280, 7706, 14824, 14271, 1844, 11102, 13600, 24939, 2669, 16067,
|
||||
16396, 1969, -1082, -6517, 16817, 2832, -545, -3283, 15713, 2843, -539, -3248,
|
||||
16104, 3336, -303, -1825, 16384, 3963, -49, -294, 16940, 4579, 165, 992,
|
||||
15711, 4599, 171, 1030, 16222, 5448, 421, 2537, 16832, 6382, 655, 3945,
|
||||
15745, 7141, 821, 4944, 16326, 7469, 888, 5343, 16611, 8624, 1100, 6622,
|
||||
17028, 10418, 1379, 8303, 15905, 11817, 1565, 9423, 16878, 14690, 1887, 11360,
|
||||
16515, 20870, 2406, 14483, 18142, 2083, -999, -6013, 19401, 3178, -375, -2257,
|
||||
17508, 3426, -264, -1589, 20054, 4027, -25, -151, 18069, 4249, 54, 326,
|
||||
18952, 5066, 314, 1890, 17711, 5402, 409, 2461, 19835, 6192, 610, 3676,
|
||||
17950, 7014, 795, 4784, 21318, 7877, 966, 5816, 17910, 9289, 1210, 7283,
|
||||
19144, 9290, 1210, 7284, 20517, 11381, 1510, 9089, 18075, 14485, 1866, 11234,
|
||||
19999, 17882, 2177, 13108, 18842, 32764, 3072, 18494,
|
||||
}
|
||||
|
||||
var table_gain_lowrates = []int16{
|
||||
10813, 28753, 2879, 17333, 20480, 2785, -570, -3431, 18841, 6594, 703, 4235,
|
||||
6225, 7413, 876, 5276, 17203, 10444, 1383, 8325, 21626, 1269, -1731, -10422,
|
||||
21135, 4423, 113, 683, 11304, 1556, -1430, -8609, 19005, 12820, 1686, 10148,
|
||||
17367, 2498, -731, -4398, 17858, 4833, 244, 1472, 9994, 2498, -731, -4398,
|
||||
17530, 7864, 964, 5802, 14254, 1884, -1147, -6907, 15892, 3153, -387, -2327,
|
||||
6717, 1802, -1213, -7303, 18186, 20193, 2357, 14189, 18022, 3031, -445, -2678,
|
||||
16711, 5857, 528, 3181, 8847, 4014, -30, -180, 15892, 8970, 1158, 6972,
|
||||
18022, 1392, -1594, -9599, 16711, 4096, 0, 0, 8192, 655, -2708, -16305,
|
||||
15237, 13926, 1808, 10884, 14254, 3112, -406, -2444, 14090, 4669, 193, 1165,
|
||||
5406, 2703, -614, -3697, 13434, 6553, 694, 4180, 12451, 901, -2237, -13468,
|
||||
12451, 2662, -637, -3833, 3768, 655, -2708, -16305, 14745, 23511, 2582, 15543,
|
||||
19169, 2457, -755, -4546, 20152, 5079, 318, 1913, 6881, 4096, 0, 0,
|
||||
20480, 8560, 1089, 6556, 19660, 737, -2534, -15255, 19005, 4259, 58, 347,
|
||||
7864, 2088, -995, -5993, 11468, 12288, 1623, 9771, 15892, 1474, -1510, -9090,
|
||||
15728, 4628, 180, 1086, 9175, 1433, -1552, -9341, 16056, 7004, 793, 4772,
|
||||
14827, 737, -2534, -15255, 15073, 2252, -884, -5321, 5079, 1228, -1780, -10714,
|
||||
13271, 17326, 2131, 12827, 16547, 2334, -831, -5002, 15073, 5816, 518, 3118,
|
||||
3932, 3686, -156, -938, 14254, 8601, 1096, 6598, 16875, 778, -2454, -14774,
|
||||
15073, 3809, -107, -646, 6062, 614, -2804, -16879, 9338, 9256, 1204, 7251,
|
||||
13271, 1761, -1247, -7508, 13271, 3522, -223, -1343, 2457, 1966, -1084, -6529,
|
||||
11468, 5529, 443, 2668, 10485, 737, -2534, -15255, 11632, 3194, -367, -2212,
|
||||
1474, 778, -2454, -14774,
|
||||
}
|
||||
|
||||
// table_gain_MR475 is the 4.75k joint pitch+code gain VQ (qgain475_tab.cpp).
|
||||
// 4 values per entry: gain_pit, gain_code, then two unused slots reused by the
|
||||
// decoder only for gain_pit/gain_code (energies are recomputed).
|
||||
var table_gain_MR475 = []int16{
|
||||
812, 128, 542, 140, 2873, 1135, 2266, 3402, 2067, 563, 12677, 647,
|
||||
4132, 1798, 5601, 5285, 7689, 374, 3735, 441, 10912, 2638, 11807, 2494,
|
||||
20490, 797, 5218, 675, 6724, 8354, 5282, 1696, 1488, 428, 5882, 452,
|
||||
5332, 4072, 3583, 1268, 2469, 901, 15894, 1005, 14982, 3271, 10331, 4858,
|
||||
3635, 2021, 2596, 835, 12360, 4892, 12206, 1704, 13432, 1604, 9118, 2341,
|
||||
3968, 1538, 5479, 9936, 3795, 417, 1359, 414, 3640, 1569, 7995, 3541,
|
||||
11405, 645, 8552, 635, 4056, 1377, 16608, 6124, 11420, 700, 2007, 607,
|
||||
12415, 1578, 11119, 4654, 13680, 1708, 11990, 1229, 7996, 7297, 13231, 5715,
|
||||
2428, 1159, 2073, 1941, 6218, 6121, 3546, 1804, 8925, 1802, 8679, 1580,
|
||||
13935, 3576, 13313, 6237, 6142, 1130, 5994, 1734, 14141, 4662, 11271, 3321,
|
||||
12226, 1551, 13931, 3015, 5081, 10464, 9444, 6706, 1689, 683, 1436, 1306,
|
||||
7212, 3933, 4082, 2713, 7793, 704, 15070, 802, 6299, 5212, 4337, 5357,
|
||||
6676, 541, 6062, 626, 13651, 3700, 11498, 2408, 16156, 716, 12177, 751,
|
||||
8065, 11489, 6314, 2256, 4466, 496, 7293, 523, 10213, 3833, 8394, 3037,
|
||||
8403, 966, 14228, 1880, 8703, 5409, 16395, 4863, 7420, 1979, 6089, 1230,
|
||||
9371, 4398, 14558, 3363, 13559, 2873, 13163, 1465, 5534, 1678, 13138, 14771,
|
||||
7338, 600, 1318, 548, 4252, 3539, 10044, 2364, 10587, 622, 13088, 669,
|
||||
14126, 3526, 5039, 9784, 15338, 619, 3115, 590, 16442, 3013, 15542, 4168,
|
||||
15537, 1611, 15405, 1228, 16023, 9299, 7534, 4976, 1990, 1213, 11447, 1157,
|
||||
12512, 5519, 9475, 2644, 7716, 2034, 13280, 2239, 16011, 5093, 8066, 6761,
|
||||
10083, 1413, 5002, 2347, 12523, 5975, 15126, 2899, 18264, 2289, 15827, 2527,
|
||||
16265, 10254, 14651, 11319, 1797, 337, 3115, 397, 3510, 2928, 4592, 2670,
|
||||
7519, 628, 11415, 656, 5946, 2435, 6544, 7367, 8238, 829, 4000, 863,
|
||||
10032, 2492, 16057, 3551, 18204, 1054, 6103, 1454, 5884, 7900, 18752, 3468,
|
||||
1864, 544, 9198, 683, 11623, 4160, 4594, 1644, 3158, 1157, 15953, 2560,
|
||||
12349, 3733, 17420, 5260, 6106, 2004, 2917, 1742, 16467, 5257, 16787, 1680,
|
||||
17205, 1759, 4773, 3231, 7386, 6035, 14342, 10012, 4035, 442, 4194, 458,
|
||||
9214, 2242, 7427, 4217, 12860, 801, 11186, 825, 12648, 2084, 12956, 6554,
|
||||
9505, 996, 6629, 985, 10537, 2502, 15289, 5006, 12602, 2055, 15484, 1653,
|
||||
16194, 6921, 14231, 5790, 2626, 828, 5615, 1686, 13663, 5778, 3668, 1554,
|
||||
11313, 2633, 9770, 1459, 14003, 4733, 15897, 6291, 6278, 1870, 7910, 2285,
|
||||
16978, 4571, 16576, 3849, 15248, 2311, 16023, 3244, 14459, 17808, 11847, 2763,
|
||||
1981, 1407, 1400, 876, 4335, 3547, 4391, 4210, 5405, 680, 17461, 781,
|
||||
6501, 5118, 8091, 7677, 7355, 794, 8333, 1182, 15041, 3160, 14928, 3039,
|
||||
20421, 880, 14545, 852, 12337, 14708, 6904, 1920, 4225, 933, 8218, 1087,
|
||||
10659, 4084, 10082, 4533, 2735, 840, 20657, 1081, 16711, 5966, 15873, 4578,
|
||||
10871, 2574, 3773, 1166, 14519, 4044, 20699, 2627, 15219, 2734, 15274, 2186,
|
||||
6257, 3226, 13125, 19480, 7196, 930, 2462, 1618, 4515, 3092, 13852, 4277,
|
||||
10460, 833, 17339, 810, 16891, 2289, 15546, 8217, 13603, 1684, 3197, 1834,
|
||||
15948, 2820, 15812, 5327, 17006, 2438, 16788, 1326, 15671, 8156, 11726, 8556,
|
||||
3762, 2053, 9563, 1317, 13561, 6790, 12227, 1936, 8180, 3550, 13287, 1778,
|
||||
16299, 6599, 16291, 7758, 8521, 2551, 7225, 2645, 18269, 7489, 16885, 2248,
|
||||
17882, 2884, 17265, 3328, 9417, 20162, 11042, 8320, 1286, 620, 1431, 583,
|
||||
5993, 2289, 3978, 3626, 5144, 752, 13409, 830, 5553, 2860, 11764, 5908,
|
||||
10737, 560, 5446, 564, 13321, 3008, 11946, 3683, 19887, 798, 9825, 728,
|
||||
13663, 8748, 7391, 3053, 2515, 778, 6050, 833, 6469, 5074, 8305, 2463,
|
||||
6141, 1865, 15308, 1262, 14408, 4547, 13663, 4515, 3137, 2983, 2479, 1259,
|
||||
15088, 4647, 15382, 2607, 14492, 2392, 12462, 2537, 7539, 2949, 12909, 12060,
|
||||
5468, 684, 3141, 722, 5081, 1274, 12732, 4200, 15302, 681, 7819, 592,
|
||||
6534, 2021, 16478, 8737, 13364, 882, 5397, 899, 14656, 2178, 14741, 4227,
|
||||
14270, 1298, 13929, 2029, 15477, 7482, 15815, 4572, 2521, 2013, 5062, 1804,
|
||||
5159, 6582, 7130, 3597, 10920, 1611, 11729, 1708, 16903, 3455, 16268, 6640,
|
||||
9306, 1007, 9369, 2106, 19182, 5037, 12441, 4269, 15919, 1332, 15357, 3512,
|
||||
11898, 14141, 16101, 6854, 2010, 737, 3779, 861, 11454, 2880, 3564, 3540,
|
||||
9057, 1241, 12391, 896, 8546, 4629, 11561, 5776, 8129, 589, 8218, 588,
|
||||
18728, 3755, 12973, 3149, 15729, 758, 16634, 754, 15222, 11138, 15871, 2208,
|
||||
4673, 610, 10218, 678, 15257, 4146, 5729, 3327, 8377, 1670, 19862, 2321,
|
||||
15450, 5511, 14054, 5481, 5728, 2888, 7580, 1346, 14384, 5325, 16236, 3950,
|
||||
15118, 3744, 15306, 1435, 14597, 4070, 12301, 15696, 7617, 1699, 2170, 884,
|
||||
4459, 4567, 18094, 3306, 12742, 815, 14926, 907, 15016, 4281, 15518, 8368,
|
||||
17994, 1087, 2358, 865, 16281, 3787, 15679, 4596, 16356, 1534, 16584, 2210,
|
||||
16833, 9697, 15929, 4513, 3277, 1085, 9643, 2187, 11973, 6068, 9199, 4462,
|
||||
8955, 1629, 10289, 3062, 16481, 5155, 15466, 7066, 13678, 2543, 5273, 2277,
|
||||
16746, 6213, 16655, 3408, 20304, 3363, 18688, 1985, 14172, 12867, 15154, 15703,
|
||||
4473, 1020, 1681, 886, 4311, 4301, 8952, 3657, 5893, 1147, 11647, 1452,
|
||||
15886, 2227, 4582, 6644, 6929, 1205, 6220, 799, 12415, 3409, 15968, 3877,
|
||||
19859, 2109, 9689, 2141, 14742, 8830, 14480, 2599, 1817, 1238, 7771, 813,
|
||||
19079, 4410, 5554, 2064, 3687, 2844, 17435, 2256, 16697, 4486, 16199, 5388,
|
||||
8028, 2763, 3405, 2119, 17426, 5477, 13698, 2786, 19879, 2720, 9098, 3880,
|
||||
18172, 4833, 17336, 12207, 5116, 996, 4935, 988, 9888, 3081, 6014, 5371,
|
||||
15881, 1667, 8405, 1183, 15087, 2366, 19777, 7002, 11963, 1562, 7279, 1128,
|
||||
16859, 1532, 15762, 5381, 14708, 2065, 20105, 2155, 17158, 8245, 17911, 6318,
|
||||
5467, 1504, 4100, 2574, 17421, 6810, 5673, 2888, 16636, 3382, 8975, 1831,
|
||||
20159, 4737, 19550, 7294, 6658, 2781, 11472, 3321, 19397, 5054, 18878, 4722,
|
||||
16439, 2373, 20430, 4386, 11353, 26526, 11593, 3068, 2866, 1566, 5108, 1070,
|
||||
9614, 4915, 4939, 3536, 7541, 878, 20717, 851, 6938, 4395, 16799, 7733,
|
||||
10137, 1019, 9845, 964, 15494, 3955, 15459, 3430, 18863, 982, 20120, 963,
|
||||
16876, 12887, 14334, 4200, 6599, 1220, 9222, 814, 16942, 5134, 5661, 4898,
|
||||
5488, 1798, 20258, 3962, 17005, 6178, 17929, 5929, 9365, 3420, 7474, 1971,
|
||||
19537, 5177, 19003, 3006, 16454, 3788, 16070, 2367, 8664, 2743, 9445, 26358,
|
||||
10856, 1287, 3555, 1009, 5606, 3622, 19453, 5512, 12453, 797, 20634, 911,
|
||||
15427, 3066, 17037, 10275, 18883, 2633, 3913, 1268, 19519, 3371, 18052, 5230,
|
||||
19291, 1678, 19508, 3172, 18072, 10754, 16625, 6845, 3134, 2298, 10869, 2437,
|
||||
15580, 6913, 12597, 3381, 11116, 3297, 16762, 2424, 18853, 6715, 17171, 9887,
|
||||
12743, 2605, 8937, 3140, 19033, 7764, 18347, 3880, 20475, 3682, 19602, 3380,
|
||||
13044, 19373, 10526, 23124,
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
// Code generated from opencore-amrnb — DO NOT EDIT.
|
||||
//
|
||||
// ROM tables extracted verbatim from the Apache-2.0 opencore-amrnb C
|
||||
// reference; element counts are verified against the C array sizes.
|
||||
|
||||
package amrnb
|
||||
|
||||
var window_200_40 = []int16{
|
||||
2621, 2623, 2629, 2638, 2651, 2668, 2689, 2713, 2741, 2772, 2808, 2847,
|
||||
2890, 2936, 2986, 3040, 3097, 3158, 3223, 3291, 3363, 3438, 3517, 3599,
|
||||
3685, 3774, 3867, 3963, 4063, 4166, 4272, 4382, 4495, 4611, 4731, 4853,
|
||||
4979, 5108, 5240, 5376, 5514, 5655, 5800, 5947, 6097, 6250, 6406, 6565,
|
||||
6726, 6890, 7057, 7227, 7399, 7573, 7750, 7930, 8112, 8296, 8483, 8672,
|
||||
8863, 9057, 9252, 9450, 9650, 9852, 10055, 10261, 10468, 10677, 10888, 11101,
|
||||
11315, 11531, 11748, 11967, 12187, 12409, 12632, 12856, 13082, 13308, 13536, 13764,
|
||||
13994, 14225, 14456, 14688, 14921, 15155, 15389, 15624, 15859, 16095, 16331, 16568,
|
||||
16805, 17042, 17279, 17516, 17754, 17991, 18228, 18465, 18702, 18939, 19175, 19411,
|
||||
19647, 19882, 20117, 20350, 20584, 20816, 21048, 21279, 21509, 21738, 21967, 22194,
|
||||
22420, 22644, 22868, 23090, 23311, 23531, 23749, 23965, 24181, 24394, 24606, 24816,
|
||||
25024, 25231, 25435, 25638, 25839, 26037, 26234, 26428, 26621, 26811, 26999, 27184,
|
||||
27368, 27548, 27727, 27903, 28076, 28247, 28415, 28581, 28743, 28903, 29061, 29215,
|
||||
29367, 29515, 29661, 29804, 29944, 30081, 30214, 30345, 30472, 30597, 30718, 30836,
|
||||
30950, 31062, 31170, 31274, 31376, 31474, 31568, 31659, 31747, 31831, 31911, 31988,
|
||||
32062, 32132, 32198, 32261, 32320, 32376, 32428, 32476, 32521, 32561, 32599, 32632,
|
||||
32662, 32688, 32711, 32729, 32744, 32755, 32763, 32767, 32767, 32741, 32665, 32537,
|
||||
32359, 32129, 31850, 31521, 31143, 30716, 30242, 29720, 29151, 28538, 27879, 27177,
|
||||
26433, 25647, 24821, 23957, 23055, 22117, 21145, 20139, 19102, 18036, 16941, 15820,
|
||||
14674, 13505, 12315, 11106, 9879, 8637, 7381, 6114, 4838, 3554, 2264, 971,
|
||||
}
|
||||
|
||||
var window_160_80 = []int16{
|
||||
2621, 2624, 2633, 2648, 2668, 2695, 2727, 2765, 2809, 2859, 2915, 2976,
|
||||
3043, 3116, 3194, 3279, 3368, 3464, 3565, 3671, 3783, 3900, 4023, 4151,
|
||||
4285, 4423, 4567, 4716, 4870, 5029, 5193, 5362, 5535, 5714, 5897, 6084,
|
||||
6277, 6473, 6674, 6880, 7089, 7303, 7521, 7742, 7968, 8197, 8430, 8667,
|
||||
8907, 9151, 9398, 9648, 9902, 10158, 10417, 10680, 10945, 11212, 11482, 11755,
|
||||
12030, 12307, 12586, 12867, 13150, 13435, 13722, 14010, 14299, 14590, 14882, 15175,
|
||||
15469, 15764, 16060, 16356, 16653, 16950, 17248, 17546, 17844, 18141, 18439, 18736,
|
||||
19033, 19330, 19625, 19920, 20214, 20507, 20799, 21090, 21380, 21668, 21954, 22239,
|
||||
22522, 22803, 23083, 23360, 23635, 23907, 24177, 24445, 24710, 24972, 25231, 25488,
|
||||
25741, 25991, 26238, 26482, 26722, 26959, 27192, 27422, 27647, 27869, 28087, 28300,
|
||||
28510, 28715, 28916, 29113, 29305, 29493, 29676, 29854, 30028, 30197, 30361, 30519,
|
||||
30673, 30822, 30966, 31105, 31238, 31366, 31489, 31606, 31718, 31825, 31926, 32021,
|
||||
32111, 32195, 32273, 32346, 32413, 32475, 32530, 32580, 32624, 32662, 32695, 32721,
|
||||
32742, 32756, 32765, 32767, 32767, 32756, 32720, 32661, 32578, 32471, 32341, 32188,
|
||||
32012, 31813, 31592, 31349, 31084, 30798, 30492, 30165, 29818, 29453, 29068, 28666,
|
||||
28247, 27810, 27358, 26891, 26408, 25913, 25404, 24883, 24350, 23807, 23255, 22693,
|
||||
22124, 21548, 20965, 20378, 19786, 19191, 18593, 17994, 17395, 16796, 16199, 15604,
|
||||
15012, 14424, 13842, 13265, 12696, 12135, 11582, 11039, 10507, 9986, 9477, 8981,
|
||||
8499, 8031, 7579, 7143, 6723, 6321, 5937, 5571, 5225, 4898, 4591, 4305,
|
||||
4041, 3798, 3577, 3378, 3202, 3048, 2918, 2812, 2729, 2669, 2633, 2621,
|
||||
}
|
||||
|
||||
var window_232_8 = []int16{
|
||||
2621, 2623, 2627, 2634, 2644, 2656, 2671, 2689, 2710, 2734, 2760, 2789,
|
||||
2821, 2855, 2893, 2933, 2975, 3021, 3069, 3120, 3173, 3229, 3288, 3350,
|
||||
3414, 3481, 3550, 3622, 3697, 3774, 3853, 3936, 4021, 4108, 4198, 4290,
|
||||
4385, 4482, 4582, 4684, 4788, 4895, 5004, 5116, 5230, 5346, 5464, 5585,
|
||||
5708, 5833, 5960, 6090, 6221, 6355, 6491, 6629, 6769, 6910, 7054, 7200,
|
||||
7348, 7498, 7649, 7803, 7958, 8115, 8274, 8434, 8597, 8761, 8926, 9093,
|
||||
9262, 9432, 9604, 9778, 9952, 10129, 10306, 10485, 10665, 10847, 11030, 11214,
|
||||
11399, 11586, 11773, 11962, 12152, 12342, 12534, 12727, 12920, 13115, 13310, 13506,
|
||||
13703, 13901, 14099, 14298, 14497, 14698, 14898, 15100, 15301, 15504, 15706, 15909,
|
||||
16112, 16316, 16520, 16724, 16928, 17132, 17337, 17541, 17746, 17950, 18155, 18359,
|
||||
18564, 18768, 18972, 19175, 19379, 19582, 19785, 19987, 20189, 20390, 20591, 20792,
|
||||
20992, 21191, 21390, 21588, 21785, 21981, 22177, 22372, 22566, 22759, 22951, 23143,
|
||||
23333, 23522, 23710, 23897, 24083, 24268, 24451, 24633, 24814, 24994, 25172, 25349,
|
||||
25525, 25699, 25871, 26042, 26212, 26380, 26546, 26711, 26874, 27035, 27195, 27353,
|
||||
27509, 27664, 27816, 27967, 28115, 28262, 28407, 28550, 28691, 28830, 28967, 29102,
|
||||
29234, 29365, 29493, 29619, 29743, 29865, 29985, 30102, 30217, 30330, 30440, 30548,
|
||||
30654, 30757, 30858, 30956, 31052, 31146, 31237, 31326, 31412, 31495, 31576, 31655,
|
||||
31730, 31804, 31874, 31942, 32008, 32071, 32131, 32188, 32243, 32295, 32345, 32392,
|
||||
32436, 32477, 32516, 32552, 32585, 32615, 32643, 32668, 32690, 32709, 32726, 32740,
|
||||
32751, 32759, 32765, 32767, 32767, 32097, 30112, 26895, 22576, 17333, 11380, 4962,
|
||||
}
|
||||
|
||||
// lag_h/lag_l: lag-window (bandwidth expansion) coefficients,
|
||||
// double precision (lag_wind_tab.cpp).
|
||||
var lag_h = []int16{32728, 32619, 32438, 32187, 31867, 31480, 31029, 30517, 29946, 29321}
|
||||
var lag_l = []int16{11904, 17280, 30720, 25856, 24192, 28992, 24384, 7360, 19520, 14784}
|
||||
@@ -0,0 +1,946 @@
|
||||
// Code generated from opencore-amrnb — DO NOT EDIT.
|
||||
//
|
||||
// ROM tables extracted verbatim from the Apache-2.0 opencore-amrnb C
|
||||
// reference; element counts are verified against the C array sizes.
|
||||
|
||||
package amrnb
|
||||
|
||||
var past_rq_init = []int16{
|
||||
-258, -318, -439, -634, -656, -773, -711, -502, -268, -193, -2, 125,
|
||||
122, -39, -9, 105, 129, 283, 372, 575, -277, -324, -197, -487,
|
||||
-445, -362, -292, -27, 177, 543, 342, 517, 516, 130, 27, -104,
|
||||
-120, -140, -74, -56, -564, -943, -1520, -965, -814, -526, -322, -2,
|
||||
159, 657, -312, -284, -386, -597, -493, -526, -418, -229, 105, 449,
|
||||
-557, -870, -1075, -919, -950, -752, -709, -316, 62, 486, -314, -191,
|
||||
-203, -330, -160, -103, -51, 131, 338, 515,
|
||||
}
|
||||
|
||||
var mean_lsf_3 = []int16{
|
||||
1546, 2272, 3778, 5488, 6972, 8382, 10047, 11229, 12766, 13714,
|
||||
}
|
||||
|
||||
var pred_fac_3 = []int16{
|
||||
9556, 10769, 12571, 13292, 14381, 11651, 10588, 9767, 8593, 6484,
|
||||
}
|
||||
|
||||
var dico1_lsf_3 = []int16{
|
||||
6, 82, -131, 154, -56, -735, 183, -65, -265, 9, -210, -361,
|
||||
113, 718, 1817, 1010, 1214, 1573, 857, 1333, 2276, 827, 1568, 1933,
|
||||
717, 1989, 2206, 838, 1172, 1823, 721, 1000, 2154, 286, 476, 1509,
|
||||
-247, -531, 230, 147, -82, 569, 26, -177, -944, -27, -273, 692,
|
||||
-164, -264, -183, 224, 790, 1039, 899, 946, 601, 485, 771, 1150,
|
||||
524, 677, 903, -140, 375, 778, 410, 676, 429, 301, 530, 1009,
|
||||
719, 646, 38, 226, 367, 40, 145, -45, -505, 290, 121, -121,
|
||||
302, 127, 166, -124, -383, -956, -358, -455, -977, 715, 878, 894,
|
||||
978, 923, 211, 477, 272, 64, 188, -78, 17, -143, -65, 38,
|
||||
643, 586, 621, -134, -426, -651, 347, 545, 2820, 1188, 2726, 2442,
|
||||
142, -80, 1735, 283, 130, 461, -262, -399, -1145, -411, 155, 430,
|
||||
329, 375, 779, 53, -226, -139, -129, -236, 1682, 285, 744, 1327,
|
||||
738, 697, 1664, 312, 409, 266, 325, 720, 135, 1, 221, 453,
|
||||
8, 203, 145, 299, 640, 760, 29, 468, 638, 103, 429, 379,
|
||||
420, 954, 932, 1326, 1210, 1258, 704, 1012, 1152, -166, -444, -266,
|
||||
-316, -130, -376, 191, 1151, 1904, -240, -543, -1260, -112, 268, 1207,
|
||||
70, 1062, 1583, 278, 1360, 1574, -258, -272, -768, 19, 563, 2240,
|
||||
-3, -265, 135, -295, -591, -388, 140, 354, -206, -260, -504, -795,
|
||||
-433, -718, -1319, 109, 331, 962, -429, -87, 652, -296, 426, 1019,
|
||||
-239, 775, 851, 489, 1334, 1073, -334, -332, 25, 543, 1206, 1807,
|
||||
326, 61, 727, 578, 849, 1405, -208, -277, 329, -152, 64, 669,
|
||||
-434, -678, -727, -454, -71, 251, 605, 480, 254, -482, 11, 996,
|
||||
-289, 395, 486, 722, 1049, 1440, -30, -316, -786, -106, -115, -619,
|
||||
861, 1474, 1412, 1055, 1366, 1184, 812, 1237, 925, 42, -251, -576,
|
||||
342, 141, -454, -168, -80, 1359, -342, -656, -1763, 100, 821, 725,
|
||||
990, 747, 800, 332, 440, 568, 663, 379, 852, 112, 165, -369,
|
||||
597, 910, 282, -8, 834, 1281, -352, 572, 695, 462, 2246, 1806,
|
||||
345, 190, 1374, 416, 915, 2166, 168, -82, 280, -516, -446, 840,
|
||||
47, 533, 44, -362, -711, -1143, 22, 193, 1472, -85, 233, 1813,
|
||||
-62, 579, 1504, 550, 944, 1749, 723, 650, 1148, 972, 884, 1395,
|
||||
-425, 643, 0, 1000, 952, 1098, 249, 1446, 672, -334, -87, 2172,
|
||||
-554, 1882, 2672, 140, 1826, 1853, 920, 1749, 2590, 1076, 1933, 2038,
|
||||
-137, -443, -1555, 1269, 1174, 468, -493, -122, 1521, -451, 1033, 1214,
|
||||
482, 1695, 1118, 815, 649, 384, -446, -692, 107, -319, -605, -118,
|
||||
-207, -505, 525, -468, -12, 2736, 75, 1934, 1305, 880, 2358, 2267,
|
||||
1285, 1575, 2004, -48, -304, -1186, -435, -461, -251, -366, -404, -547,
|
||||
-289, -605, -597, -538, -810, -165, -120, 3, 356, 639, 1241, 1502,
|
||||
96, 177, 750, -435, -585, -1174, -356, 109, -79, -485, 288, 2005,
|
||||
9, 1116, 731, 880, 2134, 946, -265, 1585, 1065, 1157, 1210, 843,
|
||||
-498, -668, 431, 374, 321, -229, 1440, 2101, 1381, 449, 461, 1155,
|
||||
-105, 39, -384, -263, 367, 182, -371, -660, 773, -188, 1151, 971,
|
||||
1333, 1632, 1435, 774, 1267, 1221, -482, -832, -1489, -237, -210, 860,
|
||||
890, 1615, 1064, 472, 1062, 1192, 185, 1077, 989, -568, -992, -1704,
|
||||
-449, -902, -2043, -142, -377, -458, -210, -554, -1029, -11, 1133, 2265,
|
||||
-329, -675, -893, -250, 657, 1187, 519, 1510, 1779, 520, 539, 1403,
|
||||
527, 1421, 1302, -563, -871, -1248, -147, -463, 879, -76, 2334, 2840,
|
||||
563, 2573, 2385, 632, 1926, 2920, 719, 2023, 1840, -545, -723, 1108,
|
||||
129, -125, 884, 1417, 1632, 925, -94, 1566, 1751, -341, 1533, 1551,
|
||||
591, 395, -274, -76, 981, 2831, 153, 2985, 1844, 1032, 2565, 2749,
|
||||
1508, 2832, 1879, 791, 1199, 538, -190, -453, 1489, -278, -548, 1158,
|
||||
-245, 1941, 2044, 1024, 1560, 1650, 512, 253, 466, -62, -323, 1151,
|
||||
-473, -376, 507, -433, 1380, 2162, 899, 1943, 1445, 134, 704, 440,
|
||||
460, 525, -28, -450, 279, 1338, 0, 971, 252, -445, -627, -991,
|
||||
-348, -602, -1424, 398, 712, 1656, -107, 314, -178, 93, 2226, 2238,
|
||||
518, 849, 656, -462, -711, -447, 174, -34, 1191, -119, 42, 1005,
|
||||
-372, 274, 758, 1036, 2352, 1838, 675, 1724, 1498, 430, 1286, 2133,
|
||||
-129, -439, 0, -373, 800, 2144, 6, 1587, 2478, 478, 596, 2128,
|
||||
-428, -736, 1505, 385, 178, 980, 139, 449, 1225, -526, -842, -982,
|
||||
145, 1554, 1242, 623, 1448, 656, 349, 1016, 1482, 31, -280, 415,
|
||||
-316, 724, 1641, 360, 1058, 556, -436, -358, 1201, -355, 1123, 1939,
|
||||
401, 1584, 2248, -527, -1012, 355, 233, 238, 2233, -550, -897, -639,
|
||||
-365, -501, 1957, 389, 1860, 1621, 162, 1132, 1264, -237, 1174, 1390,
|
||||
-640, -411, 116, -228, 1694, 2298, 1639, 2186, 2267, 562, 1273, 2658,
|
||||
323, 338, 1774, 578, 1107, 852, 22, 594, 934, -143, 718, 446,
|
||||
}
|
||||
|
||||
var dico2_lsf_3 = []int16{
|
||||
50, 71, -9, -338, -698, -1407, 102, -138, -820, -310, -469, -1147,
|
||||
414, 67, -267, 1060, 814, 1441, 1548, 1360, 1272, 1754, 1895, 1661,
|
||||
2019, 2133, 1820, 1808, 2318, 1845, 644, -93, 454, 858, 329, -136,
|
||||
489, -258, -128, -198, -745, -41, -52, -265, -985, 346, 137, 479,
|
||||
-1741, -748, -684, -1163, -1725, -367, -895, -1145, -784, -488, -946, -968,
|
||||
-85, -390, -725, 215, -340, -171, 1020, 916, 1969, 564, 179, 746,
|
||||
662, 977, 1734, 887, 622, 914, 939, 856, 1165, 309, 688, 803,
|
||||
917, 161, 570, 118, -20, -283, -816, -42, 204, -1228, -325, -462,
|
||||
-963, -202, -143, -988, -484, -361, -702, -978, -477, -302, -790, -1188,
|
||||
-100, -786, -1088, -1054, -947, -1684, -202, -843, -782, -1039, -1378, -901,
|
||||
-624, -110, -85, 356, 213, -10, -493, 364, 774, 425, 822, 479,
|
||||
-83, 557, 520, -992, -1560, -572, -603, -741, -26, -502, -638, -903,
|
||||
209, 306, 147, -316, -593, -596, -85, -211, -225, -918, -529, 117,
|
||||
233, -439, -738, 1101, 751, 633, 1457, 1716, 1511, 1765, 1457, 910,
|
||||
1122, 1156, 849, 1354, 868, 470, -871, -1150, -1796, -871, -861, -992,
|
||||
-118, 155, 212, -1051, -849, -606, -1117, -1849, -2750, -1019, -1427, -1869,
|
||||
370, -184, -414, 959, 493, 104, 958, 1039, 543, 154, 653, 201,
|
||||
1249, 507, 150, 663, 503, 230, 623, 777, 675, 659, 88, -110,
|
||||
843, 244, 224, 382, 541, 302, 724, 433, 666, 1166, 734, 341,
|
||||
-138, 20, -397, -1183, -424, -46, -321, -352, -124, 1333, 1021, 1080,
|
||||
262, 366, 723, 922, 283, -551, 31, -636, -611, -689, -697, -415,
|
||||
-952, -779, -201, -1329, -598, -359, -953, -1285, 166, 493, 305, 221,
|
||||
846, 703, 610, 840, 936, 774, -723, -1324, -1261, -357, -1025, -1388,
|
||||
-1096, -1376, -365, -1416, -1881, -608, -1798, -1727, -674, -545, -1173, -703,
|
||||
678, 786, 148, -123, 696, 1288, 644, 350, -10, 414, 614, 15,
|
||||
137, 344, -211, -814, -1512, -819, -391, -930, -588, 47, -591, -898,
|
||||
-909, -1097, -163, -1272, -1167, -157, -1464, -1525, -389, -1274, -1188, -624,
|
||||
671, 213, 454, 124, -274, -525, -729, -496, -152, -1344, 122, 135,
|
||||
-2905, -589, -394, -1728, 441, -50, 1476, 904, 787, 316, 236, -440,
|
||||
-347, 217, 413, -911, -917, 121, -455, -932, 202, -92, -465, -375,
|
||||
488, 390, 474, 876, 729, 316, -1815, -1312, -669, 87, 962, 432,
|
||||
563, -249, -1058, 250, 285, 1105, 1141, 427, 696, -1038, -1664, -1582,
|
||||
-948, 346, 160, -309, -272, -858, 670, 624, 1250, -944, -408, -666,
|
||||
-606, -320, -384, -492, 230, 65, 334, -50, -16, -16, -690, -1397,
|
||||
1791, 1716, 1399, 2478, 2063, 1404, 1245, 1471, 1426, -382, -1037, -2,
|
||||
173, -398, 1145, 1491, 2024, 1801, 772, 1274, 1506, 1429, 1735, 2001,
|
||||
1079, 1218, 1273, -1154, -1851, -1329, -808, -1133, -1096, -451, -1033, -1722,
|
||||
65, 578, -84, -1476, -2434, -1778, -765, -1366, -494, -218, -594, -931,
|
||||
337, -236, 562, 2357, 2662, 1938, 1489, 1276, 874, 189, 358, 374,
|
||||
-1519, -2281, -2346, -967, -1271, -2095, -628, -1188, -1542, 1661, 1043, 546,
|
||||
565, 1061, 732, -64, -836, -434, -436, -96, 203, 1078, 1216, 1636,
|
||||
907, 1534, 986, 326, 965, 845, 142, -84, 197, 470, 2379, 1570,
|
||||
1133, 470, 1214, 395, 1376, 1200, 1125, 1042, 348, -543, -1234, -376,
|
||||
-215, -181, 481, -1947, -1621, -210, -750, -1185, 390, 29, -399, 27,
|
||||
820, 1236, 755, 695, 979, 409, -174, 1197, 1035, 912, 1356, 1846,
|
||||
-992, -1437, 484, -1485, -1700, 208, -412, 1204, 1432, -271, 896, 1144,
|
||||
-416, 1777, 1434, -1696, -2644, -204, -1789, -1551, 1033, -1656, -1559, 1303,
|
||||
-1253, -1589, 1081, -669, -1095, -66, -682, 320, -345, 659, 305, 1069,
|
||||
-1292, -804, -19, -1635, -1291, 29, -1683, -497, 71, -287, -7, -100,
|
||||
-494, -962, -237, 852, 1881, 1740, -1217, -1387, 227, -660, 302, 373,
|
||||
96, 1087, 1257, -1074, -1669, 160, 485, 2076, 1798, -934, -220, 552,
|
||||
-596, -612, 237, 336, 1720, 879, 643, 629, 434, 1267, 522, 1633,
|
||||
15, 244, -441, 1475, 717, 184, 1819, 1590, 1709, 988, 261, 937,
|
||||
2093, 2345, 1520, 2139, 1858, 1606, -577, -579, -1203, -956, 135, -488,
|
||||
-464, 51, -338, -629, -348, -723, 1146, 2073, 1442, 2192, 1466, 911,
|
||||
-1444, -1572, -2278, 1400, 710, 1297, 1335, 633, 928, 1434, 2194, 2594,
|
||||
2422, 2204, 1881, 982, 2242, 1854, 380, 792, 1145, -63, -539, 414,
|
||||
-252, -964, -314, -1261, -683, -780, -831, -526, -1005, -1666, -1135, -424,
|
||||
-1611, -452, -299, 1268, 1048, 642, 1147, 853, 856, -675, -336, 139,
|
||||
2268, 1343, 1418, 29, 768, 797, -1224, 423, 564, -1318, -1082, 245,
|
||||
-1302, -812, 573, -1298, -1617, 646, -968, 834, 723, 993, 1652, 2027,
|
||||
-191, -817, 432, 662, 60, 198, 626, 997, 1330, 1648, 1963, 1289,
|
||||
-1597, -93, -45, -1088, 37, -84, 1653, 2607, 2337, 1065, 2040, 2377,
|
||||
1139, 2326, 2118, 859, 357, 1510, 664, 1227, 1099, 479, 1360, 912,
|
||||
1897, 1754, 2019, 1168, 1909, 1784, 399, 34, 256, -593, -304, -1053,
|
||||
547, 1694, 1407, 647, -99, -341, 1492, 1647, 1190, 38, -644, -212,
|
||||
395, 846, 222, -704, -765, -716, -724, -1964, -2804, -150, 291, -82,
|
||||
1233, 1459, 1007, -140, -155, 153, 439, 297, 1568, -1529, -410, -636,
|
||||
1536, 455, -237, -1328, -139, -260, 531, 554, 868, 269, 1264, 606,
|
||||
-233, 883, 463, 742, 600, -120, -73, 421, 212, -439, -58, 804,
|
||||
-1286, -1241, 728, 294, -490, 50, -591, -905, -1254, 42, -687, 147,
|
||||
-25, 273, 596, -311, 1213, 601, -754, 849, 584, 429, 607, 587,
|
||||
-602, -166, 461, -796, -823, 777, 1380, 910, 1755, 119, 1417, 972,
|
||||
-219, -880, -1596, -1049, -1010, 438, -713, -1379, 78, 0, -447, -1179,
|
||||
-1136, -1319, -1573, 2248, 1767, 1309, 946, 1583, 1432, 1150, 482, 436,
|
||||
-469, -1108, 618, -447, -966, 1088, -1252, -1515, -114, -1104, -2008, -579,
|
||||
210, 613, 497, -1975, -1437, 642, -1269, -856, 1011, -1646, -1185, 1063,
|
||||
-1555, -672, 1204, -1692, -1114, 623, -979, -1326, -1277, 539, -147, 894,
|
||||
-1354, -897, -434, 888, 475, 428, 153, -384, 338, -1492, -511, 359,
|
||||
-974, -1115, -470, 105, -550, 677, -937, -1145, 877, 380, -260, 210,
|
||||
1685, 924, 1256, 1775, 1190, 1095, 1419, 631, 533, 627, 299, -347,
|
||||
-411, -534, 647, -650, 29, -595, -378, -1367, 1563, 1402, 1121, 1465,
|
||||
1089, 1410, 648, -2096, -1090, -6, 311, -194, -869, -639, -831, 416,
|
||||
-1162, -1224, 1349, -1247, -941, 1813, -2193, -1987, 453, -619, -1367, -956,
|
||||
-1606, -1972, -1507, -1175, -1057, -1104, -377, 601, 201, 1876, 825, 374,
|
||||
-430, -1323, 29, -1397, -1249, -1331, -1007, -1504, 960, -1401, -2009, 197,
|
||||
-1379, -1949, -236, -1077, 123, 422, 615, 1269, 546, -306, 1526, 904,
|
||||
1194, 1788, 1177, -626, -884, -1526, 199, 766, 1504, -1065, 862, 197,
|
||||
-1034, -1773, -887, -800, 145, 599, -1134, -519, 626, -1205, -1926, 500,
|
||||
-910, -1041, -1395, -1476, -1567, -969, -523, 842, 34, 1794, 646, 862,
|
||||
-1207, -1888, -1002, -78, -9, -672, 1044, 759, 80, -600, 1139, 1019,
|
||||
57, 2000, 1422, -833, 1414, 1121, -1202, 1630, 1260, -461, 1420, 1244,
|
||||
1537, 975, 253, -283, 324, -359, 599, -195, 106, 588, 62, -587,
|
||||
-757, 645, 205, 51, 1201, 758, -1209, 673, -390, -624, 1581, 941,
|
||||
-151, 1023, 735, 2820, 1301, 690, -302, 524, -99, -900, -1588, -1189,
|
||||
1084, 251, 238, 2014, 1792, 1010, 1245, 1633, 1741, -1227, -1540, -1208,
|
||||
-621, 456, -109, 40, -65, 788, -805, -699, -1350, -583, 904, 832,
|
||||
-801, 532, 594, 1972, 1408, 1351, -1177, -1880, -2114, -773, 568, 948,
|
||||
-1015, 1079, 1260, -1111, 482, -130, 1778, 1044, 780, -1491, 245, 912,
|
||||
-316, -1141, -917, -536, -1442, -2346, -785, -1546, -1988, -2003, 257, 909,
|
||||
-1849, -633, -1209, -1538, -1918, -1054, 1606, 2239, 1576, -567, -1500, -1544,
|
||||
-1279, 195, 1369, -817, 293, 1219, -525, 630, 1197, -1698, -2425, -1840,
|
||||
-303, 731, 747, -1169, -251, 269, -950, -75, 1684, -1182, -453, 1005,
|
||||
-1599, 585, 378, -2075, -571, -427, -529, -1159, -1171, -283, -205, -564,
|
||||
-796, 1246, 717, 2277, 927, 539, -454, 559, 440, -717, 1460, 1615,
|
||||
-1030, 1052, 1610, -1169, -138, 847, 226, 39, -612, -1251, -106, -729,
|
||||
-651, 968, 1302, -714, -636, 1727, 353, 1069, 410, -798, -156, 1099,
|
||||
-574, 918, 446, -1310, 1012, 466, 1408, 1591, 765, 1429, 1380, 1757,
|
||||
1949, 1956, 2378, 1578, 2047, 2148, 916, 98, -7, 1893, 1418, 2141,
|
||||
348, 1405, 1579, 152, 1134, 1801, -267, 154, 1395, -1166, 469, 1054,
|
||||
-1142, -405, -1073, -1341, -2264, -1581, -364, 869, 1706, -1162, 549, 1550,
|
||||
-1225, -1932, -1666, -1485, -1977, -2055, -1727, -906, -98, -1897, 233, 1492,
|
||||
892, 108, -331, -1728, -1170, -1700, -1060, 1980, 1790, -1070, -1741, -1909,
|
||||
-11, 1539, 1317, -1600, 94, 497, 421, 443, -197, -1578, -349, -994,
|
||||
-599, -539, 1140, -965, -1419, -129, -1341, 175, -447, -375, 1311, 2055,
|
||||
-371, -650, -307, -1073, 605, 365, -2057, -113, 430, 652, 914, 967,
|
||||
-1012, -1586, -2323, 1505, 1248, 559, 262, -486, -401, -1727, 1342, 1546,
|
||||
50, 56, 432, -330, 119, -604, -1517, -1080, -810, 946, 1127, 1055,
|
||||
-1400, -1703, -1712, -1270, -704, -1317, 807, 1821, 1143, 2760, 1606, 2171,
|
||||
1120, 409, -150, -147, 404, 959, 2439, 1911, 2189, -906, -141, -866,
|
||||
-904, -142, -458, -557, -708, -1679, -830, -1431, -1583, -1842, -1346, -1086,
|
||||
-1604, -272, 915, -1196, 772, 1056, -638, -1234, -1897, -500, -81, -822,
|
||||
-1289, -1613, -735, -117, 785, 168, -1090, 1133, 922, -1096, -746, 1384,
|
||||
287, -547, -1063, -1376, -2201, -1204, -2176, -1570, -1757, -1511, -2241, -771,
|
||||
-1737, 1099, 830, -1588, 724, 1243, -1542, 693, 805, -1690, -240, 1665,
|
||||
-1700, -4, -668, 2149, 816, 1042, -818, -1841, 22, -764, -507, 449,
|
||||
-1151, -617, 289, -843, -1596, -240, 498, -234, -657, -752, 480, 1678,
|
||||
-319, -481, 193, -811, 171, -119, -2128, -202, -848, 1717, 1140, 1700,
|
||||
}
|
||||
|
||||
var dico3_lsf_3 = []int16{
|
||||
67, -17, 66, -12, -1690, -581, -104, -272, -1076, -1186, -1845, -376,
|
||||
-1140, -926, -420, -58, -259, -656, -1134, -553, 1788, 1227, 455, 129,
|
||||
462, 441, -240, -528, 840, 514, 130, -75, 1114, 623, 153, 216,
|
||||
1068, 564, -6, -276, 1119, 727, 190, -68, 704, 306, 119, -264,
|
||||
329, 61, -100, 156, 364, 123, 183, -208, -171, -123, 220, -65,
|
||||
-306, -62, 402, 17, -660, -938, -266, 0, 385, 235, 276, 285,
|
||||
320, 268, -336, -200, -724, 17, -84, 381, -544, 429, 494, 519,
|
||||
-117, 288, 304, 329, 643, 157, 701, 508, 1200, 625, 796, 608,
|
||||
998, 421, 492, 632, 1204, 780, 446, 132, 1257, 844, 547, 449,
|
||||
829, 658, 541, 470, 1132, 1258, 918, 639, 547, 51, 423, 279,
|
||||
9, 392, 83, 94, 542, 543, 229, -147, -198, 129, 194, -185,
|
||||
-863, -1321, -302, 30, -597, -629, -19, 114, -900, -1081, 466, 353,
|
||||
-1483, -1573, 15, -143, -1708, -2059, -751, 196, -1876, -2067, -642, -258,
|
||||
-2335, -1470, -450, -564, -584, -186, -872, -414, -1805, -988, -1125, -1310,
|
||||
-726, -1129, 28, 169, -1039, -864, -718, -246, 484, 36, -233, -49,
|
||||
265, 67, 289, 467, 178, 543, 810, 540, 84, 282, 672, 703,
|
||||
-975, -777, 129, 287, -938, -227, 955, 595, -1617, -289, 836, 649,
|
||||
-1847, -215, 1106, 718, -2034, -1085, 650, 440, -2101, -529, 907, 575,
|
||||
-2011, -336, 670, 204, -2389, -692, 360, 137, -2156, -2204, -9, 280,
|
||||
-266, 119, 39, 193, 78, -59, -120, 226, -975, -858, -781, -1095,
|
||||
-619, -413, -451, -842, -1216, -1321, -813, -883, -1376, -1615, -394, -428,
|
||||
-737, -1113, -549, -790, -880, -975, -967, -642, -985, -886, -1273, -1361,
|
||||
-473, -804, -1401, -1407, 160, -265, -919, -275, -248, -250, -718, -380,
|
||||
97, -103, -375, -229, -415, -193, -135, -555, 628, 361, 119, 216,
|
||||
579, 364, 391, 209, 634, 522, -154, -148, 526, 389, 170, 33,
|
||||
105, 267, 64, 380, -1503, -1000, -30, -369, -1070, 58, 647, 223,
|
||||
-1520, -291, 621, 307, -1531, 156, 762, 404, -2029, 141, 734, 499,
|
||||
-1849, -650, 306, 512, -187, -104, -59, 438, 134, -230, 156, -186,
|
||||
-61, -260, -16, 10, -569, -3, -421, -297, -1725, -521, -346, 178,
|
||||
-1362, -59, -44, 157, -2146, -461, -470, -349, -2170, -1, -369, -121,
|
||||
-1579, -373, -900, -1015, -1117, -591, -613, -784, -561, 122, -75, -449,
|
||||
-4, -171, -123, -372, 192, 168, -76, -132, 252, -107, 340, 210,
|
||||
392, 509, 272, 181, -109, 145, 218, 119, -416, -263, 485, 265,
|
||||
-181, -8, -286, 226, -244, -218, 69, -290, -158, 191, -1, -64,
|
||||
-592, -90, 213, -96, 255, 435, 178, -80, -369, -18, -33, -80,
|
||||
-42, 415, 140, -222, 1143, 651, 649, 329, 767, 556, 249, 235,
|
||||
948, 413, 442, 279, 141, 339, 356, 557, -470, -170, 99, 237,
|
||||
-569, -800, 352, 565, 282, 473, 470, 332, -199, -690, -1284, -917,
|
||||
-193, -426, -800, -1122, -26, -371, -490, -193, 637, 595, 519, 330,
|
||||
408, -115, 79, 12, 477, 87, -103, -376, -666, -347, -277, -291,
|
||||
-510, -481, 169, 297, -829, -738, -205, -171, -320, -540, 328, 283,
|
||||
-859, -958, 442, -2, 556, 686, 130, 56, 1383, 1012, 755, 427,
|
||||
612, 741, 628, 553, -339, -796, 134, 277, -633, -1085, -2, -246,
|
||||
-880, -1035, -1607, -1064, -994, -474, -1138, -488, -414, -795, 73, -206,
|
||||
-8, -139, 439, 204, -176, -578, 23, 131, -269, -757, -191, 245,
|
||||
-109, -338, 112, 316, 120, -406, -118, 611, -180, -186, -645, 115,
|
||||
-173, 34, -518, -489, -151, 61, -583, -844, 220, -138, -681, -1020,
|
||||
391, -17, -598, -321, 157, -295, 129, 155, -926, -875, -987, 285,
|
||||
241, -83, -125, -125, 620, 597, 432, 92, 393, 78, 409, 61,
|
||||
-393, -739, -413, -748, 83, 54, 361, 27, -1084, 130, -337, -694,
|
||||
-1565, 297, 318, -19, -1873, 36, 51, -317, -2323, -246, 231, -84,
|
||||
-2306, -783, 40, -179, -2233, -930, -474, -462, -754, -86, -288, -626,
|
||||
-2411, -455, -63, 171, -1099, -1094, -26, -143, -1193, -455, -406, -381,
|
||||
-605, -210, -96, -51, -580, -476, -276, -15, -1195, -634, -1203, -881,
|
||||
-378, -221, -669, -952, 594, 178, -403, -676, 763, 327, 601, 290,
|
||||
172, 300, 203, 157, -56, -336, 356, 24, -228, -296, -259, -29,
|
||||
-186, 263, 416, 14, -353, 373, -12, -216, 257, 96, 174, 57,
|
||||
-1526, -616, -954, -499, -497, -152, -333, 125, 105, 200, 179, -97,
|
||||
-331, -224, 765, 697, 760, 256, 301, 59, 455, -85, 204, 288,
|
||||
-514, 240, 251, -109, 256, 417, -34, -413, 101, 430, 384, 156,
|
||||
-31, -10, 206, 426, 589, 145, 143, 71, 808, 906, 333, 349,
|
||||
986, 938, 589, 331, 1300, 824, 187, 509, 1062, 653, 379, 466,
|
||||
1462, 937, 401, 274, 787, 861, 265, 2, 609, 553, 28, 305,
|
||||
926, 340, 106, 386, 241, -267, -147, 225, -178, -534, 347, 502,
|
||||
-643, -381, 397, 30, -651, -733, -435, 398, -407, -726, -484, -248,
|
||||
-789, -914, -438, -476, -498, -390, 75, -295, -964, -590, -606, 150,
|
||||
-121, -49, -155, -78, 935, 550, 389, 38, -321, 127, 424, 315,
|
||||
-285, -113, 283, 259, 658, 203, 322, 486, 903, 505, 748, 417,
|
||||
611, 423, 555, 512, 239, -83, -578, -19, -339, -731, 349, 13,
|
||||
-934, -1399, -114, -360, 107, 692, 182, 90, -1243, -1538, -1551, -725,
|
||||
-568, -903, -1363, -525, -517, -853, -861, -1004, -168, -690, -835, 63,
|
||||
-137, -556, -547, 144, -286, -817, 485, 319, -147, -408, 526, 246,
|
||||
-347, -434, 297, -28, -290, -471, -1110, -1285, -460, -359, -988, -794,
|
||||
1347, 1299, 690, 523, 1216, 1068, 1094, 757, 825, 1140, 752, 494,
|
||||
1252, 1365, 1195, 898, 521, 1053, 532, 432, -334, -216, -313, -263,
|
||||
-160, 52, -472, -155, 127, 136, -380, 44, 851, 410, -162, -489,
|
||||
123, -255, -796, -667, 1090, 917, 789, 493, 1397, 1197, 558, 202,
|
||||
-51, -118, -342, -701, 83, 108, -42, -441, 61, 95, 287, 256,
|
||||
-27, 89, 524, 531, 351, 227, 592, 545, 697, 155, -164, 307,
|
||||
638, 274, -489, -50, 754, 240, -166, -124, -116, -579, -1212, -63,
|
||||
190, -295, -1040, -1296, 147, -376, -177, -113, 841, 1241, 1051, 668,
|
||||
2, 293, 551, 304, -1096, -953, -248, 376, -750, -965, 87, 516,
|
||||
-275, -516, 689, 391, -379, -643, 876, 594, -390, -1013, -645, 573,
|
||||
-107, -568, -689, -826, -1025, -27, -328, -203, 861, 749, 548, 233,
|
||||
-1660, -1043, 451, 108, -660, -620, 430, 236, 21, -396, -1158, -631,
|
||||
1372, 1298, 967, 577, 1125, 1125, 589, 454, -323, -865, -467, 153,
|
||||
-468, -699, -804, -509, -392, -718, -204, -35, -603, -1093, -567, -162,
|
||||
-505, -1004, -102, 350, 219, 224, 423, 252, 395, 591, 608, 363,
|
||||
-746, -96, 373, 172, 171, 295, 714, 339, 233, 77, 107, 277,
|
||||
157, 153, -499, -356, 1547, 1073, 576, 494, -292, -339, -504, -592,
|
||||
-903, -72, -619, -481, -1594, -1117, -567, -254, -793, -507, -564, -291,
|
||||
-492, -532, 502, 560, -382, 427, 600, 230, -227, 477, 251, 75,
|
||||
285, 842, 813, 476, -1310, -1333, 186, 377, -587, -917, 643, 381,
|
||||
-1186, -553, 411, 82, -1127, -820, -174, -540, -604, 119, 543, 205,
|
||||
-380, 657, 909, 567, 112, -298, -374, 114, -857, -251, 56, 159,
|
||||
401, 345, -34, -140, -111, -607, 41, 614, 355, -114, -77, 474,
|
||||
578, 56, 1450, 924, 1098, 1420, 741, 400, 246, 22, 588, 313,
|
||||
-121, 327, 831, 472, -1138, -608, 856, 552, -1241, -1072, 638, 600,
|
||||
-358, 254, -333, -303, -646, 739, 358, 74, 1226, 1671, 1221, 849,
|
||||
2241, 1624, 983, 636, 1841, 1477, 749, 384, 350, 263, 87, 128,
|
||||
-1902, -941, -144, -64, -1734, -255, 288, -31, -2644, -1238, 366, 235,
|
||||
-1643, -1092, -1344, -304, -541, -1075, -1116, 123, -1178, -252, -816, -180,
|
||||
-1016, 533, 565, 233, -487, -430, -188, 334, 867, 1236, 534, 171,
|
||||
-1590, -1607, 635, 630, -2196, 310, 924, 412, -2358, -328, 956, 529,
|
||||
-2639, -377, 630, 278, -2602, 317, 799, 299, -2406, 133, 340, 31,
|
||||
-2156, -1468, 131, 125, -1184, -490, -139, 46, -744, 447, 891, 564,
|
||||
67, -451, 646, 604, -553, -429, -876, 396, 162, -66, 1305, 915,
|
||||
479, 579, 1088, 794, 450, 278, 566, 324, -1057, -154, 148, -177,
|
||||
-2545, 168, 1070, 592, -2351, -42, 819, 345, -2344, -707, 721, 250,
|
||||
-2175, -1497, -309, 122, -78, -73, 120, 173, -4, 262, -263, -261,
|
||||
-431, -64, -405, -732, -2609, 116, -83, -193, -1525, -944, -477, -725,
|
||||
-508, 307, 170, 172, 832, 417, 832, 686, -225, 177, 894, 818,
|
||||
-482, -389, 1279, 1039, -383, 201, -350, 40, 730, 635, 226, 526,
|
||||
503, 462, 338, 398, 535, 714, 40, -282, 1482, 1471, 1085, 731,
|
||||
1561, 1072, 909, 693, 1419, 1282, 889, 879, 1153, 728, 1186, 840,
|
||||
-226, 1130, 949, 689, -494, -986, -1556, -128, -568, -721, -713, -26,
|
||||
317, 524, 70, 135, -405, -865, -1766, -652, -174, -801, 885, 773,
|
||||
-153, -91, 1099, 751, -506, -1149, 853, 646, 241, 782, 519, 539,
|
||||
1853, 1700, 1101, 684, -1249, -1486, -464, 188, -893, -1409, -1312, -341,
|
||||
-135, 438, -175, 18, 1111, 976, 319, 208, -1430, -1768, 83, 458,
|
||||
-530, -1000, 307, 129, -840, -15, -29, -356, -911, -924, -1147, -242,
|
||||
-119, -528, 127, -133, -761, -765, 190, -83, -315, 895, 522, 231,
|
||||
-222, 102, -63, -428, 316, 699, 379, 70, 25, 716, 314, -108,
|
||||
507, 874, 566, 238, 108, 941, 519, 195, 425, -60, -427, 257,
|
||||
139, -103, -630, 446, 334, 370, 412, 48, -172, -690, -283, 557,
|
||||
187, -286, 158, 483, 140, 270, -344, -631, 924, 579, -116, 132,
|
||||
142, 466, -68, -64, 230, -145, -302, -542, -803, -912, 1018, 737,
|
||||
-773, 1015, 630, 297, -2596, 95, 445, 336, -2122, 491, 510, 191,
|
||||
-1253, 161, -2, -324, -1450, -633, -712, -105, -842, -254, -411, 100,
|
||||
-640, -290, 1010, 763, -650, 313, 1169, 730, 140, 505, 1030, 766,
|
||||
772, 287, 1067, 823, 495, 749, 305, 323, -164, 462, 78, 399,
|
||||
-342, -874, 69, 597, -16, 620, 621, 337, -138, -444, -265, 218,
|
||||
84, -450, 953, 666, -222, -803, 541, 604, -921, -1376, 244, 116,
|
||||
-841, -723, 630, 588, 140, 663, 294, 368, 935, 1046, 881, 759,
|
||||
1746, 1464, 916, 628, 436, 963, 281, 1, -119, 74, 542, 213,
|
||||
1, -567, 301, 241, 260, 435, 222, 396, 936, 957, 1108, 703,
|
||||
510, 506, 808, 478, 601, 694, 960, 620, 972, 741, 980, 600,
|
||||
834, 717, 767, 684, 643, 972, 935, 638, 501, 661, 720, 851,
|
||||
-105, -632, -303, -117, -429, 130, 789, 442, -522, -188, 704, 373,
|
||||
-759, 42, 814, 523, -531, -1137, 373, 578, -682, -1203, -455, 285,
|
||||
-1163, -1577, -1098, 44, 81, -82, 712, 363, 477, 246, 954, 622,
|
||||
1604, 1622, 1277, 891, 1409, 859, 924, 892, 774, 1041, 947, 1142,
|
||||
40, -546, -75, 288, -616, -106, -697, -26, -169, -160, -891, -739,
|
||||
-279, -384, -1029, -350, 1781, 1308, 1046, 816, 1580, 1533, 1472, 1178,
|
||||
1505, 1076, 1216, 899, 890, 904, 564, 654, 920, 692, 1021, 856,
|
||||
-493, 132, 177, 505, 71, 195, -28, 97, 456, 351, -164, 88,
|
||||
439, 278, -40, 350, 1395, 949, 234, -95, -805, -472, 38, -163,
|
||||
367, -98, 489, 523, 1025, 1178, 1212, 906, 319, 1314, 814, 461,
|
||||
-123, -543, -804, 447, -748, -324, -897, -1127, -737, -501, -789, -713,
|
||||
715, 777, 1239, 922, 1949, 1939, 1368, 865, 730, 880, 758, 388,
|
||||
-871, 454, 17, -251, -381, -810, -1583, 239, -521, -966, -792, 259,
|
||||
-890, -1358, -770, -73, 166, 349, -212, 323, -840, -301, 473, 435,
|
||||
-679, -464, 728, 351, -156, -199, 667, 432, 29, -252, 415, 480,
|
||||
-731, -379, 145, 559, -528, -631, -1158, -159, 445, 273, 123, 639,
|
||||
373, -126, 800, 568, 84, -162, 720, 712, -830, -536, -185, 222,
|
||||
408, 452, 501, 771, -897, -1355, -67, 442, -792, -1406, 566, 602,
|
||||
167, -326, 509, 330, -95, -626, -730, -344, 1668, 1217, 779, 455,
|
||||
1316, 828, 584, 719, 404, -31, 1013, 789, 89, 107, 891, 549,
|
||||
871, 1581, 917, 671, 866, 1479, 1289, 854, 391, 1068, 1122, 812,
|
||||
78, -562, 345, 563, 429, -103, 417, 787, -122, -437, 411, 788,
|
||||
-913, -417, 602, 754, -226, -16, 151, 760, -700, 118, -104, -14,
|
||||
-1128, 48, 284, 393, -390, -419, -639, -116, -910, 306, 316, -13,
|
||||
1207, 984, 821, 669, -1195, -693, 140, -213, -884, -416, -199, -558,
|
||||
-616, 245, -404, -664, 262, 56, -617, -724, -85, -491, -320, -656,
|
||||
-570, -831, -129, -528, -1506, -63, -367, -385, -358, -321, 4, 51,
|
||||
-366, -214, 319, 511, 146, 671, -17, -291, -110, 464, -139, -496,
|
||||
-202, 220, -312, -631, -660, -73, -655, -820, -662, -653, -1288, -857,
|
||||
-430, -953, -959, -264, -49, -468, -72, -381, -350, -563, -193, -407,
|
||||
55, -408, -803, 11, -309, 649, 188, -198, -512, 461, -79, -458,
|
||||
-1318, -263, -134, -523, -1657, -435, -495, -765, 57, -347, -414, 434,
|
||||
-1141, -242, -664, -857, 34, -68, -707, -338,
|
||||
}
|
||||
|
||||
var mr515_3_lsf = []int16{
|
||||
419, 163, -30, -262, -455, -789, -1430, -721, 1006, 664, 269, 25,
|
||||
619, 260, 183, 96, -968, -1358, -388, 135, -693, 835, 456, 154,
|
||||
1105, 703, 569, 363, 1625, 1326, 985, 748, -220, 219, 76, -208,
|
||||
-1455, -1662, 49, 149, -964, -172, -752, -336, 625, 209, -250, -66,
|
||||
-1017, -838, -2, 317, -2168, -1485, -138, 123, -1876, -2099, -521, 85,
|
||||
-967, -366, -695, -881, -921, -1011, -763, -949, -124, -256, -352, -660,
|
||||
178, 463, 354, 304, -1744, -591, -282, 79, -2249, 175, 867, 499,
|
||||
-138, -180, -181, -21, -2291, -1241, -460, -520, -771, 451, -10, -308,
|
||||
271, -65, 4, 214, -279, -435, -43, -348, -670, 35, -65, -211,
|
||||
806, 535, 85, 297, 57, 239, 722, 493, 225, 661, 840, 547,
|
||||
-540, -376, 14, 349, 469, 721, 331, 162, -544, -752, -62, -10,
|
||||
398, -88, 724, 701, -19, -533, -94, 601, 136, -71, -681, -747,
|
||||
-166, -344, 261, -50, 161, -52, 485, 337, -1675, 50, 190, -93,
|
||||
-2282, -231, -194, -82, -95, -595, -154, 128, 894, 501, 588, 457,
|
||||
-345, 206, 122, 110, -631, -227, -569, 3, 408, 239, 397, 226,
|
||||
-197, -2, 128, 491, 1281, 904, 292, 215, 538, 306, 259, 509,
|
||||
-677, -1047, 13, 321, -679, -588, -358, -212, -558, 243, 646, 479,
|
||||
486, 342, 634, 532, 107, 802, 331, 136, -112, -398, -1031, -286,
|
||||
-326, -705, 288, 272, 1299, 1144, 1178, 860, -423, 121, -385, -148,
|
||||
-295, -302, -834, -819, 16, -24, -201, -476, 555, 91, -245, 294,
|
||||
-38, -379, -962, -1221, -1191, -1518, -273, -395, -390, -1013, -645, 573,
|
||||
-1843, -1030, 505, 468, 744, 947, 609, 493, -689, -1172, -628, -135,
|
||||
-1026, 195, 411, 196, 1582, 1147, 575, 337, -1239, -777, -648, -142,
|
||||
595, 825, 967, 735, -1206, -970, -81, -342, -745, 13, -72, 375,
|
||||
454, 19, 1407, 921, -1647, -172, 861, 562, 928, 1537, 1063, 740,
|
||||
-2472, -952, 264, 82, -502, -965, -1334, 123, 867, 1236, 534, 171,
|
||||
-2320, -460, 780, 363, -1190, -617, 252, -61, -174, 34, 1011, 788,
|
||||
-2333, 247, 423, 153, -16, -355, 262, 449, -1576, -1073, -544, -371,
|
||||
-615, -305, 1051, 805, 687, 528, 6, -182, 935, 875, 1002, 809,
|
||||
199, 257, 126, 76, -584, -1138, 599, 556, -1105, -1391, -1591, -519,
|
||||
-977, -1325, 108, 347, -722, -975, 365, 101, -145, 681, 249, -153,
|
||||
0, -334, -570, 159, 412, 285, -336, -617, -953, -966, 887, 689,
|
||||
-1251, 84, -185, -398, -592, 433, 1044, 653, 85, 329, -40, 361,
|
||||
-433, -705, 466, 574, -154, 654, 592, 290, -167, 72, 349, 175,
|
||||
674, 297, 977, 720, 1235, 1204, 757, 488, -400, -269, 538, 372,
|
||||
-1350, -1387, -1194, -91, 1262, 876, 775, 700, -599, -38, -430, -722,
|
||||
1976, 1630, 991, 608, 111, 276, -226, -96, -947, -388, -11, -7,
|
||||
-303, -531, -839, 338, 1734, 1710, 1405, 1013, -516, -855, -645, 210,
|
||||
-688, -416, 513, 230, -822, -637, -1146, -320, -952, -658, -694, 183,
|
||||
-114, -623, 818, 674, -191, -204, 731, 635, 51, 1221, 883, 576,
|
||||
-954, -431, 826, 598, -342, -755, -900, -407, -1126, -354, -206, -512,
|
||||
-547, -810, -357, -620, 66, 515, -73, -410, -872, -945, -1444, -1227,
|
||||
191, -17, -544, -231, -1540, -544, -901, -886,
|
||||
}
|
||||
|
||||
var mr795_1_lsf = []int16{
|
||||
-890, -1550, -2541, -819, -970, 175, -826, -1234, -762, -599, -22, 634,
|
||||
-811, -987, -902, -323, 203, 26, -383, -235, -781, -399, 1262, 906,
|
||||
-932, -1399, -1380, -624, 93, 87, -414, -539, -691, 37, 633, 510,
|
||||
-387, -476, -1330, 399, 66, 263, -407, -49, -335, -417, 1041, 1865,
|
||||
-779, -1089, -1440, -746, -858, 832, -581, -759, -371, -673, -506, 2088,
|
||||
-560, -634, -1179, 271, 241, 14, -438, -244, -397, 463, 1202, 1047,
|
||||
-606, -797, -1438, -51, -323, 481, -224, -584, -527, 494, 881, 682,
|
||||
-433, -306, -1002, 554, 659, 222, 171, -160, -353, 681, 1798, 1565,
|
||||
-852, -1181, -1695, -336, -666, 114, -581, -756, -744, -195, 375, 497,
|
||||
-465, -804, -1098, 154, 282, -131, -50, -191, -719, 323, 732, 1542,
|
||||
-722, -819, -1404, 105, -250, 185, -178, -502, -742, 321, 510, 1111,
|
||||
-323, -567, -966, 127, 484, 338, -160, 52, -338, 732, 1367, 1554,
|
||||
-626, -802, -1696, -286, -586, 676, -695, -343, -370, -490, 295, 1893,
|
||||
-630, -574, -1014, -80, 645, -69, -6, -318, -364, 782, 1450, 1038,
|
||||
-313, -733, -1395, 120, 60, 477, -264, -585, -123, 711, 1245, 633,
|
||||
-91, -355, -1016, 771, 758, 261, 253, 81, -474, 930, 2215, 1720,
|
||||
-808, -1099, -1925, -560, -782, 169, -804, -1074, -188, -626, -55, 1405,
|
||||
-694, -716, -1194, -660, 354, 329, -514, -55, -543, 366, 1033, 1182,
|
||||
-658, -959, -1357, -55, -184, 93, -605, -286, -662, 404, 449, 827,
|
||||
-286, -350, -1263, 628, 306, 227, -16, 147, -623, 186, 923, 2146,
|
||||
-674, -890, -1606, -443, -228, 339, -369, -790, -409, 231, 86, 1469,
|
||||
-448, -581, -1061, 594, 450, -177, -124, -170, -447, 671, 1159, 1404,
|
||||
-476, -667, -1511, -77, -138, 716, -177, -372, -381, 451, 934, 915,
|
||||
-250, -432, -822, 272, 828, 446, 26, 19, -31, 698, 1692, 2168,
|
||||
-646, -977, -1924, -179, -473, 268, -379, -745, -691, 11, 127, 1033,
|
||||
-488, -917, -825, 61, 323, 135, 147, -145, -686, 685, 786, 1682,
|
||||
-506, -848, -1297, 35, 90, 222, -23, -346, -670, 455, 591, 1287,
|
||||
-203, -593, -1086, 652, 352, 437, 39, 63, -457, 841, 1265, 2105,
|
||||
-520, -882, -1584, -328, -711, 1421, -596, -342, -70, 209, 173, 1928,
|
||||
-423, -598, -921, 421, 605, -38, -2, -245, -127, 896, 1969, 1135,
|
||||
-379, -518, -1579, 173, 118, 753, -55, -381, -52, 985, 1021, 753,
|
||||
-2, -291, -891, 753, 992, 423, 264, 131, -196, 895, 2274, 2543,
|
||||
-635, -1088, -2499, -529, -982, 526, -764, -830, -548, -436, 316, 599,
|
||||
-675, -940, -746, -57, 236, -11, -201, -81, -798, 16, 845, 1558,
|
||||
-737, -985, -1212, -468, 17, 290, -279, -584, -700, 183, 822, 705,
|
||||
-265, -492, -1187, 421, 152, 468, -390, 166, -268, 39, 1550, 1868,
|
||||
-635, -966, -1571, -453, -492, 910, -284, -1027, -75, -181, -133, 1852,
|
||||
-445, -624, -1174, 420, 367, -49, -389, -212, -169, 707, 1073, 1208,
|
||||
-539, -710, -1449, 83, -163, 484, -236, -543, -355, 338, 1175, 814,
|
||||
-246, -309, -958, 606, 760, 60, 166, -8, -163, -306, 1849, 2563,
|
||||
-747, -1025, -1783, -419, -446, 209, -718, -566, -534, -506, 693, 857,
|
||||
-463, -697, -1082, 325, 431, -206, -15, -8, -763, 545, 919, 1518,
|
||||
-611, -783, -1313, 256, -55, 208, -165, -348, -662, 321, 680, 930,
|
||||
-326, -429, -951, 484, 446, 570, -197, 72, -73, 909, 1455, 1741,
|
||||
-563, -737, -1974, -124, -416, 718, -478, -404, -314, -16, 446, 1636,
|
||||
-551, -537, -750, -58, 638, 214, 55, -185, -271, 1148, 1301, 1212,
|
||||
-483, -671, -1264, 117, 285, 543, -204, -391, -111, 513, 1538, 854,
|
||||
-114, -190, -978, 877, 595, 464, 260, 260, -311, 748, 2283, 2216,
|
||||
-517, -945, -2171, -326, -708, 378, -812, -691, -232, -560, 687, 1409,
|
||||
-732, -690, -836, -359, 645, 386, -265, 62, -678, 145, 1644, 1208,
|
||||
-555, -988, -1233, -78, 14, 114, -327, -358, -489, 392, 677, 697,
|
||||
-201, -236, -1140, 693, 449, 178, -243, 256, -433, 611, 1385, 2456,
|
||||
-612, -901, -1464, -307, -17, 499, -315, -667, -254, 256, 428, 1463,
|
||||
-486, -422, -1056, 655, 370, 18, -102, -185, -276, 755, 1578, 1335,
|
||||
-488, -603, -1418, 182, -93, 870, -73, -458, -348, 835, 862, 957,
|
||||
-282, -333, -746, 547, 839, 428, 273, -89, 13, 940, 1708, 2576,
|
||||
-418, -1084, -1758, -44, -358, 259, -497, -643, -560, 99, 557, 961,
|
||||
-421, -766, -917, 295, 326, 184, 175, 15, -626, 532, 878, 1981,
|
||||
-443, -768, -1275, 221, 156, 268, 39, -363, -505, 695, 772, 1140,
|
||||
-162, -459, -912, 709, 444, 658, 25, 303, -312, 1268, 1410, 1715,
|
||||
-297, -766, -1836, -263, -108, 1070, -406, -13, -129, 57, 438, 2734,
|
||||
-374, -487, -835, 304, 696, 164, 104, -235, 5, 1611, 1900, 1399,
|
||||
-229, -582, -1325, 405, 192, 817, -87, -438, 111, 1028, 1199, 993,
|
||||
68, -175, -934, 1033, 1117, 451, 478, 200, -248, 2127, 2696, 2042,
|
||||
-835, -1323, -2131, -799, -692, 466, -812, -1032, -469, -622, 288, 920,
|
||||
-701, -841, -1070, -411, 512, 8, -390, -91, -744, -30, 1043, 1161,
|
||||
-822, -1148, -1156, -294, -46, 110, -411, -374, -678, 214, 531, 668,
|
||||
-406, -420, -1194, 487, 232, 303, -318, 91, -472, 123, 1232, 2445,
|
||||
-722, -952, -1495, -738, -675, 1332, -543, -606, -211, -95, -98, 1508,
|
||||
-549, -514, -1193, 473, 211, 73, -288, -112, -389, 537, 1332, 1258,
|
||||
-567, -755, -1545, 71, -283, 632, -170, -481, -493, 681, 1002, 817,
|
||||
-356, -331, -877, 419, 706, 346, 241, -34, -326, 377, 1950, 1883,
|
||||
-727, -1075, -1625, -233, -543, 116, -524, -806, -585, -73, 478, 729,
|
||||
-288, -925, -1143, 173, 447, -52, 68, -229, -606, 449, 529, 1797,
|
||||
-591, -875, -1363, 183, -144, 324, -103, -452, -666, 623, 488, 1176,
|
||||
-238, -511, -1004, 326, 552, 458, 136, 108, -319, 626, 1343, 1883,
|
||||
-490, -646, -1730, -186, -449, 984, -738, -76, -170, -550, 755, 2560,
|
||||
-496, -510, -947, 210, 694, -52, 84, -322, -199, 1090, 1625, 1224,
|
||||
-376, -603, -1396, 343, 74, 632, -175, -502, -32, 972, 1332, 734,
|
||||
52, -295, -1113, 1065, 918, 160, 393, 107, -397, 1214, 2649, 1741,
|
||||
-632, -1201, -1891, -719, -277, 353, -651, -880, -122, -211, 209, 1338,
|
||||
-562, -714, -1059, -208, 388, 159, -320, -61, -551, 293, 1092, 1443,
|
||||
-648, -865, -1253, -49, -143, 305, -401, -227, -585, 561, 532, 927,
|
||||
-117, -443, -1188, 507, 436, 292, -79, 233, -458, 671, 1025, 2396,
|
||||
-633, -842, -1525, -308, -286, 640, -373, -621, -407, 418, 253, 1305,
|
||||
-315, -581, -1137, 572, 685, -281, 61, -68, -371, 991, 1101, 1498,
|
||||
-493, -683, -1362, -47, 164, 704, -256, -314, -268, 631, 949, 1052,
|
||||
-118, -348, -833, 68, 1180, 568, 152, 117, 34, 1113, 1902, 2239,
|
||||
-601, -959, -1706, -143, -489, 480, -332, -655, -574, 54, 353, 1192,
|
||||
-462, -652, -796, 150, 549, 112, 195, -111, -515, 679, 1108, 1647,
|
||||
-558, -749, -1217, -9, 272, 341, -53, -265, -535, 489, 843, 1298,
|
||||
-120, -482, -1032, 632, 543, 408, 179, 306, -526, 1124, 1464, 2244,
|
||||
-417, -786, -1562, -224, -384, 1364, -377, -459, -25, 385, 489, 2174,
|
||||
-332, -651, -829, 544, 553, 61, 22, -113, -89, 1128, 1725, 1524,
|
||||
-216, -373, -1653, 161, 316, 908, -165, -222, -67, 1362, 1175, 789,
|
||||
73, -252, -767, 738, 932, 616, 362, 246, -126, 787, 2654, 3027,
|
||||
-691, -1106, -2190, -565, -588, 524, -590, -979, -490, -263, 397, 982,
|
||||
-577, -837, -945, -22, 435, -49, -190, -118, -629, -88, 1240, 1513,
|
||||
-636, -1051, -1019, -291, 189, 259, -257, -470, -629, 145, 945, 894,
|
||||
-326, -364, -1094, 543, 260, 630, -202, 189, -209, 357, 1379, 2091,
|
||||
-569, -1075, -1449, -714, -239, 919, -420, -705, -84, -109, -114, 2407,
|
||||
-413, -529, -1177, 482, 368, 131, -186, -72, -131, 861, 1255, 1220,
|
||||
-611, -658, -1341, 227, -121, 631, -176, -489, -218, 745, 1175, 957,
|
||||
-321, -148, -936, 671, 966, 216, 340, -3, -143, 469, 1848, 2437,
|
||||
-729, -961, -1683, -213, -254, 321, -511, -438, -521, -126, 725, 903,
|
||||
-340, -685, -1032, 316, 480, 20, 23, -89, -551, 353, 1051, 1789,
|
||||
-544, -757, -1364, 298, -25, 436, -100, -392, -519, 467, 754, 1078,
|
||||
-210, -398, -1078, 620, 658, 630, 33, 147, -178, 921, 1687, 1921,
|
||||
-325, -528, -1978, 2, -285, 910, -371, -490, -230, 0, 597, 2010,
|
||||
-496, -395, -834, 37, 945, 245, 181, -160, -144, 1481, 1373, 1357,
|
||||
-355, -601, -1270, 298, 322, 672, -193, -336, 77, 1089, 1533, 922,
|
||||
177, -39, -1125, 996, 781, 536, 456, 366, -432, 1415, 2440, 2279,
|
||||
-466, -758, -2325, -303, -509, 387, -727, -557, 66, -145, 643, 1248,
|
||||
-544, -676, -916, -225, 862, 588, -152, 40, -533, 423, 1423, 1558,
|
||||
-572, -843, -1145, -128, 85, 461, -238, -257, -584, 605, 748, 861,
|
||||
24, -202, -1409, 797, 487, 303, -181, 364, -182, 616, 1378, 2942,
|
||||
-494, -852, -1441, -292, 61, 812, -84, -723, -182, 555, 532, 1506,
|
||||
-365, -493, -1057, 822, 588, 11, -14, -18, -230, 1001, 1401, 1451,
|
||||
-474, -569, -1292, 302, 62, 1062, -70, -376, -222, 982, 974, 1149,
|
||||
-196, -234, -795, 479, 1098, 499, 362, 58, 70, 1147, 2069, 2857,
|
||||
-487, -878, -1824, 73, -288, 348, -358, -500, -508, 199, 721, 1242,
|
||||
-78, -697, -795, 361, 536, 196, 374, 110, -735, 847, 1051, 1896,
|
||||
-366, -713, -1182, 315, 320, 429, 72, -215, -450, 759, 886, 1363,
|
||||
-30, -428, -834, 861, 627, 796, 118, 468, -279, 1355, 1883, 1893,
|
||||
-188, -642, -1612, 63, -175, 1198, -418, -211, 51, 414, 587, 2601,
|
||||
-234, -557, -858, 424, 889, 222, 136, -101, 83, 1413, 2278, 1383,
|
||||
-84, -445, -1389, 414, 313, 1045, 29, -343, 65, 1552, 1647, 980,
|
||||
183, -91, -829, 1273, 1413, 360, 553, 272, -107, 1587, 3149, 2603,
|
||||
}
|
||||
|
||||
var mean_lsf_5 = []int16{
|
||||
1384, 2077, 3420, 5108, 6742, 8122, 9863, 11092, 12714, 13701,
|
||||
}
|
||||
|
||||
var dico1_lsf_5 = []int16{
|
||||
-451, -1065, -529, -1305, -450, -756, -497, -863, -384, -619, -413, -669,
|
||||
-317, -538, -331, -556, -414, -508, -424, -378, -274, -324, -434, -614,
|
||||
-226, -500, -232, -514, -263, -377, -298, -410, -151, -710, -174, -818,
|
||||
-149, -412, -156, -429, -288, -462, -186, -203, -170, -302, -191, -321,
|
||||
-131, -147, -297, -395, -228, -214, -245, -192, -67, -316, -71, -327,
|
||||
-104, -205, -94, -183, -143, -38, -193, -95, 16, -76, -124, -248,
|
||||
23, -237, 24, -244, 18, -136, 44, -111, -33, -24, -25, 0,
|
||||
149, 19, 23, -143, 158, -169, 174, -181, 133, -55, 165, -26,
|
||||
111, 84, 98, 75, 87, 183, -115, -11, -8, 130, 11, 170,
|
||||
254, 77, 205, 17, 183, 112, 262, 194, 202, 287, 95, 189,
|
||||
-42, -105, 234, 179, 39, 186, 163, 345, 332, 199, 299, 161,
|
||||
-54, 285, -78, 281, -133, 141, -182, 111, 249, 341, 271, 364,
|
||||
93, 403, 75, 391, 92, 510, -138, 220, -185, -29, -34, 361,
|
||||
-115, 320, 3, 554, 99, 286, 218, 591, -245, 406, -268, 453,
|
||||
0, 580, 25, 606, 275, 532, 148, 450, -73, 739, -285, 518,
|
||||
-288, 94, -203, 674, -140, -74, 205, 714, -114, 299, 176, 923,
|
||||
182, 557, 240, 705, -16, 513, 485, 593, 293, 384, 451, 617,
|
||||
-38, 50, 563, 529, 303, 209, 459, 363, 433, 452, 450, 454,
|
||||
367, 606, 477, 741, 432, 353, 368, 267, 361, 716, 273, 583,
|
||||
453, 166, 510, 172, 201, 629, 274, 191, 568, 639, 302, 298,
|
||||
634, 387, 643, 350, 587, 560, 612, 565, 600, 788, 487, 672,
|
||||
512, 1015, 321, 333, 357, 854, -125, 413, 474, 712, 17, -151,
|
||||
564, 285, 270, -241, 971, 889, 489, 220, 510, 896, 549, 924,
|
||||
327, 825, 290, 911, 540, 1108, 158, 805, 199, 957, 511, 730,
|
||||
100, 874, 13, 791, 435, 632, 676, 972, 249, 900, 467, 1218,
|
||||
781, 1074, 585, 785, -23, 669, 267, 1043, 619, 1084, 615, 1145,
|
||||
622, 905, 916, 1049, 80, 331, 584, 1075, 89, 639, 988, 961,
|
||||
770, 720, 798, 699, 492, 447, 899, 627, 271, 1188, 725, 1333,
|
||||
87, 603, 832, 1603, 616, 1127, 890, 1505, 1000, 1156, 866, 1009,
|
||||
995, 827, 1149, 858, 817, 1450, 773, 1320, 500, 1389, 312, 1153,
|
||||
-20, 1084, 64, 1283, 2, 1172, 399, 1869, 514, 1706, 502, 1636,
|
||||
886, 1522, 416, 600, 1131, 1350, 1275, 1390, 889, 1795, 914, 1766,
|
||||
227, 1183, 1250, 1826, 505, 1854, 919, 2353, -199, 431, 152, 1735,
|
||||
-213, -28, 392, 1334, -153, -52, 978, 1151, -323, -400, 813, 1703,
|
||||
-136, 84, 1449, 2015, -331, -143, -137, 1192, -256, 534, -157, 1031,
|
||||
-307, -439, 542, 731, -329, -420, -97, 616, -362, -168, -322, 366,
|
||||
-247, -110, -211, 89, -196, -309, 20, 59, -364, -463, -286, 89,
|
||||
-336, 175, -432, 141, -379, -190, -434, -196, -79, 150, -278, -227,
|
||||
-280, 166, -555, -422, -155, 541, -366, 54, -29, -83, -301, -774,
|
||||
186, 628, -397, -264, 242, 293, -197, -585, 124, 410, 53, -133,
|
||||
10, 340, -570, -1065, 65, -446, 68, -493, 383, 937, -357, -711,
|
||||
-359, -250, -677, -1068, 292, -26, 363, 6, 607, 1313, -127, -10,
|
||||
1513, 1886, 713, 972, 1469, 2181, 1443, 2016,
|
||||
}
|
||||
|
||||
var dico2_lsf_5 = []int16{
|
||||
-1631, -1600, -1796, -2290, -1027, -1770, -1100, -2025, -1277, -1388, -1367, -1534,
|
||||
-947, -1461, -972, -1524, -999, -1222, -1020, -1172, -815, -987, -992, -1371,
|
||||
-1216, -1006, -1289, -1094, -744, -1268, -755, -1293, -862, -923, -905, -984,
|
||||
-678, -1051, -685, -1050, -1087, -985, -1062, -679, -989, -641, -1127, -976,
|
||||
-762, -654, -890, -806, -833, -1091, -706, -629, -621, -806, -640, -812,
|
||||
-775, -634, -779, -543, -996, -565, -1075, -580, -546, -611, -572, -619,
|
||||
-760, -290, -879, -526, -823, -462, -795, -253, -553, -415, -589, -439,
|
||||
-533, -340, -692, -935, -505, -772, -702, -1131, -263, -306, -971, -483,
|
||||
-445, -74, -555, -548, -614, -129, -693, -234, -396, -246, -475, -250,
|
||||
-265, -404, -376, -514, -417, -510, -300, -313, -334, -664, -463, -814,
|
||||
-386, -704, -337, -615, -234, -201, -233, -239, -167, -567, -203, -619,
|
||||
-147, -415, -115, -352, -166, -750, -171, -761, -270, -879, -264, -903,
|
||||
-367, -744, 43, -475, 14, -653, 43, -670, 11, -448, -59, -521,
|
||||
-126, -119, -155, -613, -42, -863, -27, -931, 136, -483, 183, -468,
|
||||
55, -298, 55, -304, 313, -609, 313, -720, 322, -167, 100, -541,
|
||||
-3, -119, -111, -187, 233, -236, 260, -234, 26, -165, 134, -45,
|
||||
-40, -549, 360, -203, 378, -388, 450, -383, 275, 20, 182, -103,
|
||||
246, -111, 431, 37, 462, -146, 487, -157, -284, -59, 503, -184,
|
||||
24, 53, -3, 54, 122, 259, 333, 66, 484, 104, 436, 68,
|
||||
195, 116, 190, 206, 269, -9, 482, 352, 382, 285, 399, 277,
|
||||
452, 256, 69, 186, 13, 297, -13, 259, -95, 30, 56, 394,
|
||||
196, 425, 205, 456, 281, 577, 15, 191, 375, 290, 407, 576,
|
||||
-56, 227, 544, 405, 0, 549, -92, 528, -229, 351, -245, 338,
|
||||
-362, 435, 167, 527, -75, 302, 91, 824, 129, 599, 496, 679,
|
||||
186, 749, 153, 737, -281, 600, -348, 615, -236, 769, 41, 881,
|
||||
38, 890, -220, 841, -357, 883, -393, 903, -634, 474, -444, 850,
|
||||
-175, 678, -493, 242, -519, 785, -714, 582, -541, 366, -543, 434,
|
||||
-597, 500, -765, 222, -702, 917, -743, 962, -869, 501, -899, 548,
|
||||
-379, 200, -435, 157, -819, 214, -861, 157, -614, 40, -632, 94,
|
||||
-883, -54, -741, 516, -501, 298, -614, -171, -870, -161, -865, -23,
|
||||
-818, 93, -1015, -267, -662, -359, -549, 2, -442, -121, -377, 0,
|
||||
-227, 33, -414, -126, -129, 212, -934, 34, -1082, -282, -1119, -268,
|
||||
-710, -825, -420, -191, -1076, -928, -917, -93, -628, -358, 97, 7,
|
||||
-206, -393, -101, 24, -203, 38, -168, 83, -599, -423, -279, 426,
|
||||
-700, 118, -75, 206, -981, -673, -680, 417, -367, 37, -279, 474,
|
||||
-129, -318, 319, 296, -626, -39, 343, 602, -696, -39, -303, 940,
|
||||
104, 233, -380, 137, -36, 269, -75, -214, 120, 43, -529, -477,
|
||||
459, 164, -202, -229, -49, -167, 609, 792, 98, -220, 915, 148,
|
||||
293, 283, 869, 91, 575, 394, 326, -78, 717, 67, 365, -323,
|
||||
616, -36, 731, 27, 619, 238, 632, 273, 448, 99, 801, 476,
|
||||
869, 273, 685, 64, 789, 72, 1021, 217, 793, 459, 734, 360,
|
||||
646, 480, 360, 322, 429, 464, 638, 430, 756, 363, 1000, 404,
|
||||
683, 528, 602, 615, 655, 413, 946, 687, 937, 602, 904, 604,
|
||||
555, 737, 786, 662, 467, 654, 362, 589, 929, 710, 498, 478,
|
||||
415, 420, 693, 883, 813, 683, 781, 925, 913, 939, 726, 732,
|
||||
491, 853, 531, 948, 734, 963, 315, 808, 761, 755, 1144, 760,
|
||||
655, 1076, 826, 1057, 1091, 838, 1003, 808, 1047, 1133, 659, 1101,
|
||||
992, 1050, 1074, 1075, 971, 694, 1226, 1054, 571, 841, 884, 1404,
|
||||
1379, 1096, 1080, 861, 1231, 735, 1284, 760, 1272, 991, 1367, 1053,
|
||||
1257, 700, 1050, 534, 988, 453, 1264, 599, 1140, 679, 1621, 815,
|
||||
1384, 521, 1317, 393, 1564, 805, 1448, 686, 1068, 648, 875, 307,
|
||||
1083, 361, 1047, 317, 1417, 964, 675, 571, 1152, 79, 1114, -47,
|
||||
1530, 311, 1721, 314, 1166, 689, 514, -94, 349, 282, 1412, 328,
|
||||
1025, 487, -65, 57, 805, 970, 36, 62, 769, -263, 791, -346,
|
||||
637, 699, -137, 620, 534, 541, -735, 194, 711, 300, -268, -863,
|
||||
926, 769, -708, -428, 506, 174, -892, -630, 435, 547, -1435, -258,
|
||||
621, 471, -1018, -1368, -393, 521, -920, -686, -25, 20, -982, -1156,
|
||||
340, 9, -1558, -1135, -352, 48, -1579, -402, -887, 6, -1156, -888,
|
||||
-548, -352, -1643, -1168, -159, 610, -2024, -963, -225, 193, -1656, -1960,
|
||||
-245, -493, -964, -1680, -936, -635, -1299, -1744, -1388, -604, -1540, -835,
|
||||
-1397, -135, -1588, -290, -1670, -712, -2011, -1632, -1663, -27, -2258, -811,
|
||||
-1157, 184, -1265, 189, -1367, 586, -2011, 201, -790, 712, -1210, 3,
|
||||
-1033, 808, -1251, 830, -111, 635, -1636, 447, -463, -949, -445, -928,
|
||||
-504, -1162, -501, -1211, 144, -351, -372, -1052, -283, -1059, -279, -1123,
|
||||
-575, -1438, -587, -1614, -935, -984, 229, 690, -921, -719, -403, 1362,
|
||||
-685, -465, 874, 397, -509, -46, 317, 1334, -485, 456, 813, 439,
|
||||
-411, 339, 898, 1067, -425, 46, 1441, 497, -909, -800, 1465, 1046,
|
||||
-254, -321, 1430, 1165, 68, 350, 1034, 666, 370, 11, 1311, 790,
|
||||
143, 232, 1041, 1562, -114, 663, 1616, 1078, 454, 579, 1275, 1040,
|
||||
-76, 909, 752, 1067, 153, 512, 348, 1214, 614, 385, 1843, 808,
|
||||
269, 1034, 203, 1086, 652, 1017, 1783, 1130, 429, 1327, 387, 1384,
|
||||
-49, 1183, -72, 1215, -416, 1001, 544, 1749, -352, 1223, -502, 1199,
|
||||
-589, 569, -227, 1630, -142, 1578, -230, 1715, -714, 1288, -838, 1398,
|
||||
1131, 1357, -208, 1232, 437, 965, -929, 818, 811, 1410, 859, 1507,
|
||||
164, 1212, 1387, 1793, 484, 1874, 456, 2063, 996, 1170, 1326, 1402,
|
||||
1316, 1360, 1135, 1262, 1234, 1618, 1361, 1768, 1421, 1227, 1584, 1347,
|
||||
854, 672, 1685, 1566, 1139, 1270, 2016, 1825, 1773, 1581, 1532, 1460,
|
||||
1487, 946, 1659, 1021, 1744, 1212, 1392, 977, 1772, 1161, 1826, 1164,
|
||||
1718, 1429, 1973, 1591, 1185, 864, 2132, 1061, 1799, 814, 1838, 757,
|
||||
2104, 1315, 2054, 1258, 2113, 915, 2331, 930, 1467, 1147, 2590, 1439,
|
||||
2245, 1744, 2090, 1620, 2358, 1454, 2666, 1506, 1876, 1837, 2070, 1975,
|
||||
1739, 1577, 682, 1289, 1584, 2045, 1454, 2098, 2498, 2004, 2711, 2066,
|
||||
726, 1588, 2756, 2336, 228, 847, 2456, 1659, 36, 301, 1942, 1957,
|
||||
-446, -96, 2154, 1396, 1533, 1101, 14, 608, -923, -732, 1383, 1982,
|
||||
1345, 952, -680, 321, 1281, 1268, -1594, 365, 941, 946, -1737, -822,
|
||||
2374, 2787, 1821, 2788,
|
||||
}
|
||||
|
||||
var dico3_lsf_5 = []int16{
|
||||
-1812, -2275, -1879, -2537, -1640, -1848, -1695, -2004, -1220, -1912, -1221, -2106,
|
||||
-1559, -1588, -1573, -1556, -1195, -1615, -1224, -1727, -1359, -1151, -1616, -1948,
|
||||
-1274, -1391, -1305, -1403, -1607, -1179, -1676, -1311, -1443, -1478, -1367, -898,
|
||||
-1256, -1059, -1331, -1134, -982, -1133, -1149, -1504, -1080, -1308, -1020, -1183,
|
||||
-980, -1486, -967, -1495, -988, -922, -1047, -1077, -838, -1179, -858, -1222,
|
||||
-1131, -1041, -1064, -767, -872, -1157, -701, -880, -706, -906, -774, -1016,
|
||||
-578, -1080, -801, -1478, -591, -1111, -592, -1146, -713, -1388, -640, -1376,
|
||||
-597, -1059, -416, -903, -686, -832, -661, -708, -444, -868, -490, -921,
|
||||
-374, -776, -619, -1170, -585, -549, -769, -795, -435, -659, -530, -741,
|
||||
-498, -837, -357, -597, -279, -871, -243, -887, -282, -665, -280, -667,
|
||||
-165, -560, -394, -903, -362, -410, -448, -583, -409, -574, -313, -357,
|
||||
-637, -548, -570, -436, -896, -504, -382, -757, -58, -481, -165, -618,
|
||||
-191, -374, -234, -382, -222, -683, -25, -480, -418, -359, -730, -353,
|
||||
-324, -157, -432, -322, -394, -303, -284, -104, -601, -289, -556, -196,
|
||||
-588, -150, -659, -608, -473, -24, -68, -448, -474, -8, -506, -45,
|
||||
-748, -184, -844, -252, -901, -91, -584, -97, -652, 138, -764, -131,
|
||||
-678, -12, -670, 165, -259, -3, -840, -107, -909, 37, -992, 44,
|
||||
-854, -415, -839, 13, -1001, -271, -1026, -309, -798, -478, -832, -488,
|
||||
-943, 168, -1112, -387, -1185, -101, -1183, -40, -941, -316, -1030, -770,
|
||||
-1044, -625, -1081, -538, -1224, -299, -1312, -436, -1197, -663, -1167, -161,
|
||||
-1216, -690, -1237, -831, -1432, -720, -1403, -493, -898, -740, -922, -801,
|
||||
-1102, -402, -1579, -964, -1061, -638, -1269, -1438, -1499, -934, -1502, -895,
|
||||
-1598, -564, -1723, -717, -606, -597, -1166, -1085, -1369, -468, -1946, -1493,
|
||||
-1838, -953, -1932, -931, -1499, -188, -1635, -421, -1457, -338, -1448, -22,
|
||||
-1942, -422, -2006, -249, -496, -114, -1910, -755, -1289, 174, -1451, -109,
|
||||
-482, -257, -1221, -508, -1617, 151, -1694, 208, -654, 107, -1651, 29,
|
||||
-1141, 279, -1215, 306, -1228, -506, -730, -175, -1236, -101, -969, 551,
|
||||
-870, 278, -823, 315, -563, 376, -1051, 228, -507, 280, -599, 281,
|
||||
-758, 253, -305, 379, -755, -134, -611, 660, -824, 536, -817, 646,
|
||||
-413, 49, -341, 177, -453, 526, -482, 589, -71, 339, -657, 264,
|
||||
-244, 295, -237, 315, -387, 569, -506, -9, -377, 14, -160, 661,
|
||||
-216, 40, -308, -46, 95, 214, -242, 167, -86, 192, -56, 27,
|
||||
-76, 31, 36, 309, -106, -182, -113, 74, -441, -22, 23, 139,
|
||||
81, -11, 44, 15, -87, -137, -118, -207, -158, -58, 272, -92,
|
||||
-156, -441, 8, -136, 128, -221, 101, -218, 40, -197, -76, -456,
|
||||
9, -445, 33, -423, 226, 60, 73, -222, 156, -399, 280, -318,
|
||||
245, -341, 166, -499, 339, -190, 327, -219, 325, -137, -89, -596,
|
||||
100, -627, 144, -677, 487, 28, 252, -391, 214, -41, 282, -28,
|
||||
99, -286, 331, 49, 459, -388, 565, -369, 436, 28, 336, -9,
|
||||
397, -167, 618, 34, 596, -17, 561, -140, 299, 79, 522, 125,
|
||||
203, 2, 244, 288, 255, 211, 175, 82, 596, 187, 517, 108,
|
||||
381, 255, 365, 297, 497, 352, 327, -82, 25, 210, 371, 245,
|
||||
261, 3, 545, 449, 140, 294, 44, 295, 212, 347, 244, 494,
|
||||
331, 528, 201, 307, 349, 411, 613, 284, 614, 413, 464, 322,
|
||||
624, 397, 97, 200, -160, 384, 149, 362, 495, 525, 269, 585,
|
||||
33, 491, -121, 433, 427, 611, 498, 516, 171, 443, 497, 666,
|
||||
440, 275, 566, 575, 146, 639, 155, 670, -33, 173, 212, 696,
|
||||
-166, 601, -191, 695, -489, 503, 175, 742, 214, 476, 372, 1083,
|
||||
578, 530, 586, 777, 425, 874, 315, 841, 374, 848, -165, 565,
|
||||
35, 991, -39, 1062, 329, 712, 786, 840, 645, 795, 661, 676,
|
||||
571, 918, 632, 1079, 673, 817, 318, 388, 874, 1012, 564, 848,
|
||||
880, 620, 557, 479, 671, 453, 692, 468, 840, 642, 844, 645,
|
||||
506, 428, 897, 567, 837, 387, 962, 499, 691, 561, 939, 926,
|
||||
783, 296, 790, 268, 1028, 530, 874, 329, 548, 143, 675, 291,
|
||||
503, 66, 1041, 359, 786, 97, 805, 33, 837, 470, 511, 49,
|
||||
1092, 327, 1174, 323, 3, 242, 872, 474, 689, 429, 1329, 678,
|
||||
1042, 620, 1109, 664, 321, 193, 889, 950, 1153, 874, 893, 635,
|
||||
877, 862, 948, 913, 1293, 665, 1320, 639, 997, 793, 1402, 1030,
|
||||
1176, 1012, 1110, 959, 1410, 925, 1403, 915, 543, 862, 1116, 1222,
|
||||
835, 1190, 835, 1190, 959, 1148, 1147, 1376, 1300, 1193, 1415, 1231,
|
||||
1335, 1341, 746, 1092, 1711, 1283, 1389, 1073, 1334, 1566, 1153, 1475,
|
||||
1645, 1137, 1825, 1220, 1056, 1382, 1521, 1730, 1632, 1545, 1620, 1542,
|
||||
855, 1596, 865, 1667, 693, 885, 1716, 1519, 1167, 1296, 2209, 1760,
|
||||
1952, 1493, 2020, 1482, 1534, 1866, 1694, 2008, 1566, 748, 1761, 825,
|
||||
294, 1392, 1084, 2058, 621, 1315, 365, 1287, 198, 1028, 488, 1408,
|
||||
249, 403, 1014, 1561, 324, 363, 1645, 1044, 193, 367, 2034, 1859,
|
||||
-251, 579, 750, 994, -243, 30, 1325, 879, -28, -169, 624, 917,
|
||||
-453, 159, 186, 1370, -614, 6, 537, 392, -94, -291, 781, 229,
|
||||
-128, -298, 245, 491, -701, -648, 972, 789, -501, -640, 178, 255,
|
||||
-365, -390, -255, 317, -958, -294, -191, 228, -775, -447, 157, -237,
|
||||
-657, -720, -407, 92, -117, -611, 334, -230, -679, -1084, -144, -317,
|
||||
-901, -861, -738, -360, -85, -727, -90, -787, 100, -22, -391, -263,
|
||||
-56, -73, -337, -754, 5, -189, -706, -624, 89, -344, -135, -1113,
|
||||
-353, -237, -684, -1135, -275, -1102, -269, -1203, 152, 145, -722, -1232,
|
||||
49, 80, -1248, -776, -248, 391, -732, -547, 469, 218, -255, -864,
|
||||
69, 366, -166, -485, -688, 191, -1212, -1196, -170, -169, -1308, -1631,
|
||||
321, 470, -1419, -1243, -64, 272, -1361, -248, 492, 565, -721, -609,
|
||||
195, 485, -573, -133, 427, 202, -171, -118, 199, 575, 2, -31,
|
||||
694, 755, -1366, -39, 552, 557, -489, 271, 680, 537, 13, -453,
|
||||
855, 954, -133, -52, -81, 738, -1169, 637, 1055, 1059, -95, 676,
|
||||
1259, 1081, 489, 305, -449, 954, -534, 996, -969, 866, -1058, 1059,
|
||||
-1294, 618, -1416, 617, -458, 1366, -159, 1821, -774, -528, -14, 1110,
|
||||
-1202, -901, -772, 433, -1256, -1255, -1011, -302, -602, -585, -759, -1618,
|
||||
-760, -1549, -840, -1921, -816, -539, -1769, -2235, -227, -36, -2034, -1831,
|
||||
-2107, -1126, -2471, -1816, -1470, 252, -2701, -415, -571, -467, 1509, 1554,
|
||||
2180, 1975, 2326, 2020,
|
||||
}
|
||||
|
||||
var dico4_lsf_5 = []int16{
|
||||
-1857, -1681, -1857, -1755, -2056, -1150, -2134, -1654, -1619, -1099, -1704, -1131,
|
||||
-1345, -1608, -1359, -1638, -1338, -1293, -1325, -1265, -1664, -1649, -1487, -851,
|
||||
-1346, -1832, -1413, -2188, -1282, -681, -1785, -1649, -966, -1082, -1183, -1676,
|
||||
-1054, -1073, -1142, -1158, -1207, -744, -1274, -997, -934, -1383, -927, -1416,
|
||||
-1010, -1305, -783, -955, -1049, -900, -993, -817, -737, -823, -972, -1189,
|
||||
-738, -1094, -738, -1154, -784, -801, -810, -786, -892, -520, -1000, -818,
|
||||
-644, -965, -577, -882, -541, -694, -671, -917, -595, -642, -646, -615,
|
||||
-956, -621, -925, -515, -727, -483, -815, -485, -840, -578, -440, -713,
|
||||
-578, -325, -657, -670, -386, -570, -441, -666, -514, -787, -392, -529,
|
||||
-522, -453, -487, -423, -616, -585, -617, -157, -662, -268, -680, -348,
|
||||
-322, -323, -632, -444, -304, -430, -332, -458, -277, -468, -659, -793,
|
||||
-319, -636, -227, -554, -373, -347, -334, -210, -456, -192, -530, -242,
|
||||
-216, -198, -366, -370, -338, -161, -409, -748, -107, -380, -294, -643,
|
||||
-223, -665, -234, -741, -141, -496, -130, -510, -139, -327, -172, -305,
|
||||
-306, -580, -164, -263, -262, -172, -67, -402, 31, -366, -10, -436,
|
||||
-86, -527, 71, -377, -22, -609, -12, -678, -67, -319, 63, -191,
|
||||
35, -181, -39, -242, 126, -167, -140, -544, 155, -297, 174, -297,
|
||||
38, -8, 117, -380, 197, -452, 240, -522, 223, -103, 110, -187,
|
||||
87, -155, 169, -47, 157, 26, -83, -100, 128, 80, 209, -62,
|
||||
6, 7, 22, 5, 318, -20, 248, -45, -200, -63, 156, -69,
|
||||
250, -183, 369, -126, -113, -76, -142, -122, -64, -254, -31, 35,
|
||||
-177, -71, -7, 171, 93, 27, 108, 212, -330, -209, -123, -70,
|
||||
-279, 95, -96, 20, -188, -61, -314, 87, -300, -78, -354, -134,
|
||||
11, 122, -140, 122, -275, 152, -293, 140, -82, 138, -321, -111,
|
||||
-480, -156, -359, 76, -254, -40, -635, -96, -522, 79, -507, 8,
|
||||
-268, 303, -539, 68, -446, 61, -522, 306, 111, 189, -435, 122,
|
||||
-379, 166, -571, -398, -632, -74, -747, -95, -455, 194, -952, 83,
|
||||
-798, 192, -755, 192, -781, -162, -619, 234, -663, -297, -488, -109,
|
||||
-964, -132, -838, -68, -843, 58, -1112, -86, -805, -299, -944, -253,
|
||||
-778, -50, -965, -549, -352, -98, -992, -343, -1117, -315, -1117, -307,
|
||||
-1155, -374, -637, -230, -1166, -43, -1299, -100, -925, -393, -1274, -600,
|
||||
-689, -130, -1479, -312, -1321, -254, -1464, -442, -1292, -613, -1261, -503,
|
||||
-1501, -368, -1322, 26, -1432, -66, -1743, -161, -1644, -467, -1760, -548,
|
||||
-1393, -568, -1556, -871, -1495, -1034, -1387, -571, -1917, -528, -1783, -123,
|
||||
-1897, -231, -2054, -323, -2052, -906, -1976, -567, -1917, -620, -2047, -989,
|
||||
-1077, -370, -2031, -704, -2355, -749, -2740, -1089, -1909, 159, -2012, 248,
|
||||
-626, -123, -2339, -962, -669, -408, -1379, -1174, -452, -364, -1044, -735,
|
||||
-132, 183, -1620, -752, -547, -307, -777, -1261, -98, 41, -880, -1091,
|
||||
-257, 97, -1602, -1833, 31, -26, -644, -561, -180, -546, -385, -1095,
|
||||
-410, -802, -414, -827, -457, -970, -490, -1109, -215, -916, -144, -937,
|
||||
-493, -1269, -517, -1507, 181, 101, -332, -889, -836, -937, -559, -429,
|
||||
-629, -547, -183, -337, -545, -82, -250, -286, 5, -132, -348, -252,
|
||||
-293, -472, -158, 100, -29, 197, -236, -424, -861, -213, -140, -7,
|
||||
-427, -443, 187, -97, -684, -736, -293, 258, -368, -152, -150, 392,
|
||||
-609, 175, -142, 299, -138, 152, -119, 329, -486, -52, 293, 198,
|
||||
-183, 117, 175, 331, -58, -274, 231, 300, -288, 330, -305, 372,
|
||||
-111, 409, -9, 423, 83, 256, 67, 367, -19, 248, 91, 113,
|
||||
-35, 406, -191, 154, 238, 296, 5, 197, 141, 221, 313, 198,
|
||||
211, 421, 244, 334, 88, 426, -243, 454, 202, 552, -5, 403,
|
||||
291, 185, 219, 301, 251, 138, 128, 69, 197, 288, -140, -61,
|
||||
188, 361, 197, 598, 442, 273, 290, 143, 472, 482, 157, 370,
|
||||
415, 321, 372, 385, 402, 552, 155, 24, 550, 263, -11, 21,
|
||||
360, 227, 147, -254, 424, 97, 366, -13, 375, 141, 449, 232,
|
||||
396, 507, 474, 272, 701, 324, 362, -47, 587, 148, 543, 69,
|
||||
400, -51, 561, 59, 220, -10, 352, 147, 206, 211, 653, 185,
|
||||
563, 297, 565, 284, 594, 121, 766, 192, 398, 118, 642, 434,
|
||||
233, 264, 481, 467, 129, -165, 699, 239, 90, 26, 342, 474,
|
||||
-55, 27, 388, 94, -172, 0, 725, 379, -60, 337, 370, 465,
|
||||
95, 319, 806, 595, 78, 260, 497, 851, 210, 560, 458, 574,
|
||||
-464, 202, 497, 625, -202, 152, 48, 712, -20, 566, 100, 715,
|
||||
455, 468, 411, 605, 319, 646, 195, 615, 401, 538, 680, 739,
|
||||
201, 667, 434, 954, 454, 425, 646, 491, 606, 681, 416, 508,
|
||||
497, 822, 426, 815, 660, 647, 628, 716, 697, 466, 618, 457,
|
||||
685, 460, 365, 309, 721, 567, 836, 601, 609, 300, 825, 459,
|
||||
943, 687, 681, 533, 915, 598, 591, 243, 876, 451, 874, 420,
|
||||
786, 317, 732, 220, 922, 317, 1108, 367, 531, 466, 1028, 649,
|
||||
1053, 615, 1034, 553, 829, 602, 1021, 799, 927, 803, 878, 763,
|
||||
799, 496, 1373, 773, 585, 770, 803, 930, 1099, 793, 1222, 862,
|
||||
1209, 895, 1025, 727, 772, 845, 1172, 1115, 867, 1021, 830, 1013,
|
||||
841, 910, 506, 703, 1239, 1077, 620, 819, 1196, 1083, 1155, 1081,
|
||||
1142, 907, 1547, 1121, 1309, 648, 1343, 612, 1484, 988, 1479, 937,
|
||||
985, 1328, 955, 1341, 429, 910, 841, 1338, 564, 1179, 412, 1156,
|
||||
1427, 1320, 1434, 1330, 640, 760, 1726, 1410, 190, 555, 1073, 1005,
|
||||
426, 257, 839, 980, 235, 231, 1520, 1167, 109, 293, 1014, 1569,
|
||||
305, 142, 1148, 539, -291, -108, 1213, 972, 22, -216, 667, 828,
|
||||
-482, 438, 453, 1431, -581, -422, 789, 387, -358, -454, 174, 780,
|
||||
-36, -372, 390, -134, -629, 160, -306, 751, -1258, -331, 177, 522,
|
||||
-248, 574, -251, 639, -531, 407, -596, 394, -419, 789, -617, 801,
|
||||
-986, 399, -857, 727, -7, 518, -703, 310, -1143, -24, -1002, 287,
|
||||
-960, 363, -1299, 312, -1534, 245, -1557, 305, 28, 153, -859, -175,
|
||||
-33, 332, -1398, -154, 212, 410, -593, -197, -1092, -704, -904, -65,
|
||||
282, 367, -918, -686, 345, 93, -258, -357, 696, 644, -693, -28,
|
||||
448, 493, -273, 193, 527, 546, -243, -513, 384, -136, 273, -353,
|
||||
512, -142, 537, -198, 941, 750, 83, 248, 578, 861, -56, 592,
|
||||
842, 44, 892, 24, 33, 890, -16, 982, 831, 1398, 1535, 1898,
|
||||
1716, 1376, 1948, 1465,
|
||||
}
|
||||
|
||||
var dico5_lsf_5 = []int16{
|
||||
-1002, -929, -1096, -1203, -641, -931, -604, -961, -779, -673, -835, -788,
|
||||
-416, -664, -458, -766, -652, -521, -662, -495, -1023, -509, -1023, -428,
|
||||
-444, -552, -368, -449, -479, -211, -1054, -903, -316, -249, -569, -591,
|
||||
-569, -275, -541, -191, -716, -188, -842, -264, -333, -248, -318, -228,
|
||||
-275, 1, -567, -228, -115, -221, -238, -374, -197, -507, -222, -579,
|
||||
-258, -432, -61, -244, -345, 2, -338, 39, -215, -169, -58, 0,
|
||||
-56, -6, -203, -131, 1, -186, -5, -211, 6, -380, 11, -418,
|
||||
-116, 131, -134, 113, 89, -4, 71, -2, -19, -192, 262, 24,
|
||||
189, 151, -133, -109, 186, -153, 166, -219, 37, 139, 193, 171,
|
||||
337, 124, 158, -61, 141, 226, -13, 190, 231, 34, 354, 109,
|
||||
316, 201, 244, 164, 330, -85, 390, -84, 254, 327, 257, 335,
|
||||
491, 147, 476, 105, 54, 77, 437, 370, 421, 314, 449, 342,
|
||||
329, 126, 673, 292, 571, 388, 243, 193, 653, 320, 621, 280,
|
||||
194, 380, 517, 581, 45, 323, 111, 422, 489, 395, 734, 534,
|
||||
622, 546, 486, 502, 318, 572, 189, 550, 385, 422, -157, 153,
|
||||
-125, 382, -197, 386, -263, 334, 228, 697, -188, 1, 51, 297,
|
||||
-507, 213, -376, 397, -24, 255, -547, 89, -502, -94, 387, 179,
|
||||
-620, 68, -684, 112, -642, -350, -260, 172, -438, -324, 264, 648,
|
||||
-964, -4, -1121, 7, -134, 134, -1133, -306, 143, 96, -420, -497,
|
||||
-1221, -350, -1527, -685, -161, 72, 873, 691, 732, 283, 921, 353,
|
||||
334, 475, 1095, 821, 864, 524, 843, 497, 714, 711, 788, 750,
|
||||
1076, 714, 1204, 753,
|
||||
}
|
||||
|
||||
var lspLsfTable = []int16{
|
||||
32767, 32729, 32610, 32413, 32138, 31786, 31357, 30853, 30274, 29622, 28899, 28106,
|
||||
27246, 26320, 25330, 24279, 23170, 22006, 20788, 19520, 18205, 16846, 15447, 14010,
|
||||
12540, 11039, 9512, 7962, 6393, 4808, 3212, 1608, 0, -1608, -3212, -4808,
|
||||
-6393, -7962, -9512, -11039, -12540, -14010, -15447, -16846, -18205, -19520, -20788, -22006,
|
||||
-23170, -24279, -25330, -26320, -27246, -28106, -28899, -29622, -30274, -30853, -31357, -31786,
|
||||
-32138, -32413, -32610, -32729, -32768,
|
||||
}
|
||||
|
||||
var lspLsfSlope = []int16{
|
||||
-26887, -8812, -5323, -3813, -2979, -2444, -2081, -1811, -1608, -1450, -1322, -1219,
|
||||
-1132, -1059, -998, -946, -901, -861, -827, -797, -772, -750, -730, -713,
|
||||
-699, -687, -677, -668, -662, -657, -654, -652, -652, -654, -657, -662,
|
||||
-668, -677, -687, -699, -713, -730, -750, -772, -797, -827, -861, -901,
|
||||
-946, -998, -1059, -1132, -1219, -1322, -1450, -1608, -1811, -2081, -2444, -2979,
|
||||
-3813, -5323, -8812, -26887,
|
||||
}
|
||||
|
||||
var lsp_init_data = []int16{
|
||||
30000, 26000, 21000, 15000, 8000, 0, -8000, -15000, -21000, -26000,
|
||||
}
|
||||
|
||||
var grid = []int16{
|
||||
32760, 32723, 32588, 32364, 32051, 31651, 31164, 30591, 29935, 29196, 28377, 27481,
|
||||
26509, 25465, 24351, 23170, 21926, 20621, 19260, 17846, 16384, 14876, 13327, 11743,
|
||||
10125, 8480, 6812, 5126, 3425, 1714, 0, -1714, -3425, -5126, -6812, -8480,
|
||||
-10125, -11743, -13327, -14876, -16384, -17846, -19260, -20621, -21926, -23170, -24351, -25465,
|
||||
-26509, -27481, -28377, -29196, -29935, -30591, -31164, -31651, -32051, -32364, -32588, -32723,
|
||||
-32760,
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// Code generated from opencore-amrnb — DO NOT EDIT.
|
||||
//
|
||||
// ROM tables extracted verbatim from the Apache-2.0 opencore-amrnb C
|
||||
// reference; element counts are verified against the C array sizes.
|
||||
|
||||
package amrnb
|
||||
|
||||
var log2_tbl = []int16{
|
||||
0, 1455, 2866, 4236, 5568, 6863, 8124, 9352, 10549, 11716, 12855, 13967,
|
||||
15054, 16117, 17156, 18172, 19167, 20142, 21097, 22033, 22951, 23852, 24735, 25603,
|
||||
26455, 27291, 28113, 28922, 29716, 30497, 31266, 32023, 32767,
|
||||
}
|
||||
|
||||
var pow2_tbl = []int16{
|
||||
16384, 16743, 17109, 17484, 17867, 18258, 18658, 19066, 19484, 19911, 20347, 20792,
|
||||
21247, 21713, 22188, 22674, 23170, 23678, 24196, 24726, 25268, 25821, 26386, 26964,
|
||||
27554, 28158, 28774, 29405, 30048, 30706, 31379, 32066, 32767,
|
||||
}
|
||||
|
||||
var inv_sqrt_tbl = []int16{
|
||||
32767, 31790, 30894, 30070, 29309, 28602, 27945, 27330, 26755, 26214, 25705, 25225,
|
||||
24770, 24339, 23930, 23541, 23170, 22817, 22479, 22155, 21845, 21548, 21263, 20988,
|
||||
20724, 20470, 20225, 19988, 19760, 19539, 19326, 19119, 18919, 18725, 18536, 18354,
|
||||
18176, 18004, 17837, 17674, 17515, 17361, 17211, 17064, 16921, 16782, 16646, 16514,
|
||||
16384,
|
||||
}
|
||||
|
||||
var sqrt_l_tbl = []int16{
|
||||
16384, 16888, 17378, 17854, 18318, 18770, 19212, 19644, 20066, 20480, 20886, 21283,
|
||||
21674, 22058, 22435, 22806, 23170, 23530, 23884, 24232, 24576, 24915, 25249, 25580,
|
||||
25905, 26227, 26545, 26859, 27170, 27477, 27780, 28081, 28378, 28672, 28963, 29251,
|
||||
29537, 29819, 30099, 30377, 30652, 30924, 31194, 31462, 31727, 31991, 32252, 32511,
|
||||
32767, 32767,
|
||||
}
|
||||
|
||||
var overflow_tbl = []int32{
|
||||
2147483647, 1073741823, 536870911, 268435455, 134217727, 67108863, 33554431, 16777215, 8388607, 4194303, 2097151, 1048575,
|
||||
524287, 262143, 131071, 65535, 32767, 16383, 8191, 4095, 2047, 1023, 511, 255,
|
||||
127, 63, 31, 15, 7, 3, 1, 0,
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// Code generated from opencore-amrnb corrwght_tab.cpp. DO NOT EDIT.
|
||||
|
||||
package amrnb
|
||||
|
||||
// corrweight is the open-loop pitch weighting curve used by Pitch_ol_wgh (MR102).
|
||||
var corrweight = [251]int16{
|
||||
20473, 20506, 20539, 20572, 20605, 20644, 20677, 20716, 20749, 20788,
|
||||
20821, 20860, 20893, 20932, 20972, 21011, 21050, 21089, 21129, 21168,
|
||||
21207, 21247, 21286, 21332, 21371, 21417, 21456, 21502, 21542, 21588,
|
||||
21633, 21679, 21725, 21771, 21817, 21863, 21909, 21961, 22007, 22059,
|
||||
22105, 22158, 22210, 22263, 22315, 22367, 22420, 22472, 22531, 22584,
|
||||
22643, 22702, 22761, 22820, 22879, 22938, 23003, 23062, 23128, 23193,
|
||||
23252, 23324, 23390, 23455, 23527, 23600, 23665, 23744, 23816, 23888,
|
||||
23967, 24045, 24124, 24202, 24288, 24366, 24451, 24537, 24628, 24714,
|
||||
24805, 24904, 24995, 25094, 25192, 25297, 25395, 25500, 25611, 25723,
|
||||
25834, 25952, 26070, 26188, 26313, 26444, 26575, 26706, 26844, 26988,
|
||||
27132, 27283, 27440, 27597, 27761, 27931, 28108, 28285, 28475, 28665,
|
||||
28869, 29078, 29295, 29524, 29760, 30002, 30258, 30527, 30808, 31457,
|
||||
32767, 32767, 32767, 32767, 32767, 32767, 32767, 31457, 30808, 30527,
|
||||
30258, 30002, 29760, 29524, 29295, 29078, 28869, 28665, 28475, 28285,
|
||||
28108, 27931, 27761, 27597, 27440, 27283, 27132, 26988, 26844, 26706,
|
||||
26575, 26444, 26313, 26188, 26070, 25952, 25834, 25723, 25611, 25500,
|
||||
25395, 25297, 25192, 25094, 24995, 24904, 24805, 24714, 24628, 24537,
|
||||
24451, 24366, 24288, 24202, 24124, 24045, 23967, 23888, 23816, 23744,
|
||||
23665, 23600, 23527, 23455, 23390, 23324, 23252, 23193, 23128, 23062,
|
||||
23003, 22938, 22879, 22820, 22761, 22702, 22643, 22584, 22531, 22472,
|
||||
22420, 22367, 22315, 22263, 22210, 22158, 22105, 22059, 22007, 21961,
|
||||
21909, 21863, 21817, 21771, 21725, 21679, 21633, 21588, 21542, 21502,
|
||||
21456, 21417, 21371, 21332, 21286, 21247, 21207, 21168, 21129, 21089,
|
||||
21050, 21011, 20972, 20932, 20893, 20860, 20821, 20788, 20749, 20716,
|
||||
20677, 20644, 20605, 20572, 20539, 20506, 20473, 20434, 20401, 20369,
|
||||
20336,
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
// Code generated from opencore-amrnb (3GPP TS 26.101) — DO NOT EDIT.
|
||||
//
|
||||
// Per-mode RFC 4867 / IETF bit-reordering tables (bitreorder_tab.cpp) and the
|
||||
// parameter bit widths (bitno_tab.cpp). reorderBits[m][k] is the ETS serial bit
|
||||
// index that supplies the k-th transmitted (IETF storage order) speech bit, so
|
||||
// the table is a permutation of 0..modeBits[m]-1. bitno[m] lists the bit width
|
||||
// of each encoder parameter, MSB-first, summing to modeBits[m].
|
||||
|
||||
package amrnb
|
||||
|
||||
// bitno gives the bit width of each serial parameter per speech mode (0..7).
|
||||
var bitno = [numSpeechModes][]int16{
|
||||
Mode0475: {8, 8, 7, 8, 7, 2, 8, 4, 7, 2, 4, 7, 2, 8, 4, 7, 2},
|
||||
Mode0515: {8, 8, 7, 8, 7, 2, 6, 4, 7, 2, 6, 4, 7, 2, 6, 4, 7, 2, 6},
|
||||
Mode0590: {8, 9, 9, 8, 9, 2, 6, 4, 9, 2, 6, 8, 9, 2, 6, 4, 9, 2, 6},
|
||||
Mode0670: {8, 9, 9, 8, 11, 3, 7, 4, 11, 3, 7, 8, 11, 3, 7, 4, 11, 3, 7},
|
||||
Mode0740: {8, 9, 9, 8, 13, 4, 7, 5, 13, 4, 7, 8, 13, 4, 7, 5, 13, 4, 7},
|
||||
Mode0795: {9, 9, 9, 8, 13, 4, 4, 5, 6, 13, 4, 4, 5, 8, 13, 4, 4, 5, 6, 13, 4, 4, 5},
|
||||
Mode1020: {8, 9, 9, 8, 1, 1, 1, 1, 10, 10, 7, 7, 5, 1, 1, 1, 1, 10, 10, 7, 7, 8, 1, 1, 1, 1, 10, 10, 7, 7, 5, 1, 1, 1, 1, 10, 10, 7, 7},
|
||||
Mode1220: {7, 8, 9, 8, 6, 9, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 5, 6, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 5, 9, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 5, 6, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 5},
|
||||
}
|
||||
|
||||
// reorderBits maps transmitted bit position -> ETS serial bit index per mode.
|
||||
var reorderBits = [numSpeechModes][]int16{
|
||||
Mode0475: {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
23, 24, 25, 26, 27, 28, 48, 49, 61, 62, 82, 83, 47, 46, 45, 44,
|
||||
81, 80, 79, 78, 17, 18, 20, 22, 77, 76, 75, 74, 29, 30, 43, 42,
|
||||
41, 40, 38, 39, 16, 19, 21, 50, 51, 59, 60, 63, 64, 72, 73, 84,
|
||||
85, 93, 94, 32, 33, 35, 36, 53, 54, 56, 57, 66, 67, 69, 70, 87,
|
||||
88, 90, 91, 34, 55, 68, 89, 37, 58, 71, 92, 31, 52, 65, 86,
|
||||
},
|
||||
Mode0515: {
|
||||
7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8,
|
||||
23, 24, 25, 26, 27, 46, 65, 84, 45, 44, 43, 64, 63, 62, 83, 82,
|
||||
81, 102, 101, 100, 42, 61, 80, 99, 28, 47, 66, 85, 18, 41, 60, 79,
|
||||
98, 29, 48, 67, 17, 20, 22, 40, 59, 78, 97, 21, 30, 49, 68, 86,
|
||||
19, 16, 87, 39, 38, 58, 57, 77, 35, 54, 73, 92, 76, 96, 95, 36,
|
||||
55, 74, 93, 32, 51, 33, 52, 70, 71, 89, 90, 31, 50, 69, 88, 37,
|
||||
56, 75, 94, 34, 53, 72, 91,
|
||||
},
|
||||
Mode0590: {
|
||||
0, 1, 4, 5, 3, 6, 7, 2, 13, 15, 8, 9, 11, 12, 14, 10,
|
||||
16, 28, 74, 29, 75, 27, 73, 26, 72, 30, 76, 51, 97, 50, 71, 96,
|
||||
117, 31, 77, 52, 98, 49, 70, 95, 116, 53, 99, 32, 78, 33, 79, 48,
|
||||
69, 94, 115, 47, 68, 93, 114, 46, 67, 92, 113, 19, 21, 23, 22, 18,
|
||||
17, 20, 24, 111, 43, 89, 110, 64, 65, 44, 90, 25, 45, 66, 91, 112,
|
||||
54, 100, 40, 61, 86, 107, 39, 60, 85, 106, 36, 57, 82, 103, 35, 56,
|
||||
81, 102, 34, 55, 80, 101, 42, 63, 88, 109, 41, 62, 87, 108, 38, 59,
|
||||
84, 105, 37, 58, 83, 104,
|
||||
},
|
||||
Mode0670: {
|
||||
0, 1, 4, 3, 5, 6, 13, 7, 2, 8, 9, 11, 15, 12, 14, 10,
|
||||
28, 82, 29, 83, 27, 81, 26, 80, 30, 84, 16, 55, 109, 56, 110, 31,
|
||||
85, 57, 111, 48, 73, 102, 127, 32, 86, 51, 76, 105, 130, 52, 77, 106,
|
||||
131, 58, 112, 33, 87, 19, 23, 53, 78, 107, 132, 21, 22, 18, 17, 20,
|
||||
24, 25, 50, 75, 104, 129, 47, 72, 101, 126, 54, 79, 108, 133, 46, 71,
|
||||
100, 125, 128, 103, 74, 49, 45, 70, 99, 124, 42, 67, 96, 121, 39, 64,
|
||||
93, 118, 38, 63, 92, 117, 35, 60, 89, 114, 34, 59, 88, 113, 44, 69,
|
||||
98, 123, 43, 68, 97, 122, 41, 66, 95, 120, 40, 65, 94, 119, 37, 62,
|
||||
91, 116, 36, 61, 90, 115,
|
||||
},
|
||||
Mode0740: {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 26, 87, 27, 88, 28, 89, 29, 90, 30, 91, 51, 80, 112, 141, 52,
|
||||
81, 113, 142, 54, 83, 115, 144, 55, 84, 116, 145, 58, 119, 59, 120, 21,
|
||||
22, 23, 17, 18, 19, 31, 60, 92, 121, 56, 85, 117, 146, 20, 24, 25,
|
||||
50, 79, 111, 140, 57, 86, 118, 147, 49, 78, 110, 139, 48, 77, 53, 82,
|
||||
114, 143, 109, 138, 47, 76, 108, 137, 32, 33, 61, 62, 93, 94, 122, 123,
|
||||
41, 42, 43, 44, 45, 46, 70, 71, 72, 73, 74, 75, 102, 103, 104, 105,
|
||||
106, 107, 131, 132, 133, 134, 135, 136, 34, 63, 95, 124, 35, 64, 96, 125,
|
||||
36, 65, 97, 126, 37, 66, 98, 127, 38, 67, 99, 128, 39, 68, 100, 129,
|
||||
40, 69, 101, 130,
|
||||
},
|
||||
Mode0795: {
|
||||
8, 7, 6, 5, 4, 3, 2, 14, 16, 9, 10, 12, 13, 15, 11, 17,
|
||||
20, 22, 24, 23, 19, 18, 21, 56, 88, 122, 154, 57, 89, 123, 155, 58,
|
||||
90, 124, 156, 52, 84, 118, 150, 53, 85, 119, 151, 27, 93, 28, 94, 29,
|
||||
95, 30, 96, 31, 97, 61, 127, 62, 128, 63, 129, 59, 91, 125, 157, 32,
|
||||
98, 64, 130, 1, 0, 25, 26, 33, 99, 34, 100, 65, 131, 66, 132, 54,
|
||||
86, 120, 152, 60, 92, 126, 158, 55, 87, 121, 153, 117, 116, 115, 46, 78,
|
||||
112, 144, 43, 75, 109, 141, 40, 72, 106, 138, 36, 68, 102, 134, 114, 149,
|
||||
148, 147, 146, 83, 82, 81, 80, 51, 50, 49, 48, 47, 45, 44, 42, 39,
|
||||
35, 79, 77, 76, 74, 71, 67, 113, 111, 110, 108, 105, 101, 145, 143, 142,
|
||||
140, 137, 133, 41, 73, 107, 139, 37, 69, 103, 135, 38, 70, 104, 136,
|
||||
},
|
||||
Mode1020: {
|
||||
7, 6, 5, 4, 3, 2, 1, 0, 16, 15, 14, 13, 12, 11, 10, 9,
|
||||
8, 26, 27, 28, 29, 30, 31, 115, 116, 117, 118, 119, 120, 72, 73, 161,
|
||||
162, 65, 68, 69, 108, 111, 112, 154, 157, 158, 197, 200, 201, 32, 33, 121,
|
||||
122, 74, 75, 163, 164, 66, 109, 155, 198, 19, 23, 21, 22, 18, 17, 20,
|
||||
24, 25, 37, 36, 35, 34, 80, 79, 78, 77, 126, 125, 124, 123, 169, 168,
|
||||
167, 166, 70, 67, 71, 113, 110, 114, 159, 156, 160, 202, 199, 203, 76, 165,
|
||||
81, 82, 92, 91, 93, 83, 95, 85, 84, 94, 101, 102, 96, 104, 86, 103,
|
||||
87, 97, 127, 128, 138, 137, 139, 129, 141, 131, 130, 140, 147, 148, 142, 150,
|
||||
132, 149, 133, 143, 170, 171, 181, 180, 182, 172, 184, 174, 173, 183, 190, 191,
|
||||
185, 193, 175, 192, 176, 186, 38, 39, 49, 48, 50, 40, 52, 42, 41, 51,
|
||||
58, 59, 53, 61, 43, 60, 44, 54, 194, 179, 189, 196, 177, 195, 178, 187,
|
||||
188, 151, 136, 146, 153, 134, 152, 135, 144, 145, 105, 90, 100, 107, 88, 106,
|
||||
89, 98, 99, 62, 47, 57, 64, 45, 63, 46, 55, 56,
|
||||
},
|
||||
Mode1220: {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 23,
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 38, 141, 39,
|
||||
142, 40, 143, 41, 144, 42, 145, 43, 146, 44, 147, 45, 148, 46, 149, 47,
|
||||
97, 150, 200, 48, 98, 151, 201, 49, 99, 152, 202, 86, 136, 189, 239, 87,
|
||||
137, 190, 240, 88, 138, 191, 241, 91, 194, 92, 195, 93, 196, 94, 197, 95,
|
||||
198, 29, 30, 31, 32, 33, 34, 35, 50, 100, 153, 203, 89, 139, 192, 242,
|
||||
51, 101, 154, 204, 55, 105, 158, 208, 90, 140, 193, 243, 59, 109, 162, 212,
|
||||
63, 113, 166, 216, 67, 117, 170, 220, 36, 37, 54, 53, 52, 58, 57, 56,
|
||||
62, 61, 60, 66, 65, 64, 70, 69, 68, 104, 103, 102, 108, 107, 106, 112,
|
||||
111, 110, 116, 115, 114, 120, 119, 118, 157, 156, 155, 161, 160, 159, 165, 164,
|
||||
163, 169, 168, 167, 173, 172, 171, 207, 206, 205, 211, 210, 209, 215, 214, 213,
|
||||
219, 218, 217, 223, 222, 221, 73, 72, 71, 76, 75, 74, 79, 78, 77, 82,
|
||||
81, 80, 85, 84, 83, 123, 122, 121, 126, 125, 124, 129, 128, 127, 132, 131,
|
||||
130, 135, 134, 133, 176, 175, 174, 179, 178, 177, 182, 181, 180, 185, 184, 183,
|
||||
188, 187, 186, 226, 225, 224, 229, 228, 227, 232, 231, 230, 235, 234, 233, 238,
|
||||
237, 236, 96, 199,
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// 本文件是本项目为 vendored 包**新增**的导出桥,**不是**上游 `v1.0.0` 的内容。
|
||||
// 出处与许可证见同目录 VENDORED.md(上游 = github.com/VoiceBlender/goamr-nb
|
||||
// v1.0.0,Apache-2.0,LICENSE / NOTICE 已逐字保留)。
|
||||
//
|
||||
// 为什么需要它:上游公开 API 以 **RTP 载荷**(RFC 4867 的 octet-aligned /
|
||||
// bandwidth-efficient 打包)为输入;而 `.amr` **存储格式**(RFC 4867 §5)是
|
||||
// 「`#!AMR\n` 魔数 + 每帧『1 字节 ToC + ceil(bits/8) 字节语音位』」,没有 CMR
|
||||
// 字节、也不用 F 位。调用方要按 ToC 分帧就必须知道每种帧类型占多少字节,而这张
|
||||
// 表(RFC 4867 Table 1a)在上游包内是未导出的。
|
||||
//
|
||||
// 两条路:① 在本项目的 codec 里再抄一份规格表(两处表格会各自漂移);
|
||||
// ② 在这里开一个只做转发的薄导出。本包选 ②:全仓只有一份帧长表,且它来自被
|
||||
// vendored 的那份实现本身。
|
||||
package amrnb
|
||||
|
||||
// FrameBytesByFT 返回帧类型 ft(ToC 字节的高 4 位,0..15)在 **octet-aligned**
|
||||
// 打包下占用的字节数(**不含** ToC 字节本身),以及该帧类型是否合法。
|
||||
//
|
||||
// 语音模式返回 ceil(bits/8)(RFC 4867 Table 1a:12/13/15/17/19/20/26/31),
|
||||
// SID(FT 8)返回 5,SPEECH_LOST(FT 14)与 NO_DATA(FT 15)返回 0,
|
||||
// 保留值(FT 9..13)返回 false。
|
||||
func FrameBytesByFT(ft int) (int, bool) { return frameBytesByFT(ft) }
|
||||
Reference in new issue
Block a user