feat(audio): real noise suppression via vendored RNNoise (send + receive)
The two-sided NR plumbing (RemoteStream::recv_ns + the per-listener vc_set_remote_stream noise_reduction toggle) was wired but inert: ApmProcessor::create() returned a no-op passthrough, because the originally-planned webrtc-audio-processing has no working Windows/macOS build. Drop in RNNoise as the real backend behind the same ApmProcessor interface, lighting up both NR paths. - Vendor RNNoise (BSD-3 + CC0) at third_party/rnnoise/ — the vcpkg port is !windows !arm, so it can't cover our primary targets. Shrunk int8 model (78MB -> 11.7MB via upstream scripts/shrink_model.sh), built as a standalone C static lib with no RTCD (portable scalar path on x86, auto-NEON on arm64) under -DDISABLE_DEBUG_FLOAT. Model is baked in (rnnoise_create(NULL)); no runtime file. - New RnnoiseProcessor (core/src/audio/apm_processor.cpp) selected by ApmProcessor::create() when VOICECAT_HAS_NS. Mono/48kHz/480-sample; our clock is fixed 48kHz and Opus frame sizes are multiples of 480, so no resampling. RT-safe: allocates at construction, lock-free in the capture/playback callbacks. - Receive-side: lit up via the factory; gated to mono streams (a stereo stream is a screen-audio share, not voice). - Send-side (new): vc_set_input_noise_reduction(client, enable) ABI + vc_client::mic_ns_, run before input gain/VAD in on_capture_frame. A stereo mic is downmixed to mono ONLY when NR is on — with NR off a stereo mic keeps full stereo (never collapse mic quality unasked). - Enable C as a project language for the vendored lib. - New noise_suppression test: white noise through ApmProcessor::create() drops ~99.9% RMS. ctest --preset dev green, 28/28. windows-client DLL builds clean with vc_set_input_noise_reduction exported, system-only deps. - Docs synced: voice.md §10, tech-stack.md §1/§5, third_party/README.md, vcpkg.json note, PROGRESS.md, CLAUDE.md. Client on/off UI toggles (Windows/macOS/iOS) are the remaining follow-up. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -8,10 +8,13 @@ and what's next* read [`PROGRESS.md`](PROGRESS.md); for *design* read [`docs/`](
|
|||||||
> server-mute, channel CRUD, in-app account management, disconnect/keepalive/reaper. Windows
|
> server-mute, channel CRUD, in-app account management, disconnect/keepalive/reaper. Windows
|
||||||
> WinForms C# client shipped (M4). **macOS AppKit client shipped** — `VoiceCatMac.xcodeproj`
|
> WinForms C# client shipped (M4). **macOS AppKit client shipped** — `VoiceCatMac.xcodeproj`
|
||||||
> at `clients/apple/macOS/`. **iOS SwiftUI client shipped** — `VoiceCatiOS.xcodeproj` at
|
> at `clients/apple/macOS/`. **iOS SwiftUI client shipped** — `VoiceCatiOS.xcodeproj` at
|
||||||
> `clients/apple/iOS/`. `ctest --preset dev` green — 27/27 tests.
|
> `clients/apple/iOS/`. `ctest --preset dev` green — 28/28 tests.
|
||||||
> External PCM feed/tap API (`vc_stream_feed_pcm` + `vc_set_pcm_sink`) shipped.
|
> External PCM feed/tap API (`vc_stream_feed_pcm` + `vc_set_pcm_sink`) shipped.
|
||||||
> **Screen-audio sharing shipped on macOS (ScreenCaptureKit) and iOS (ReplayKit Broadcast
|
> **Screen-audio sharing shipped on macOS (ScreenCaptureKit) and iOS (ReplayKit Broadcast
|
||||||
> Upload Extension → host App Group ring → `vc_stream_feed_pcm`).** See [`PROGRESS.md`](PROGRESS.md).
|
> Upload Extension → host App Group ring → `vc_stream_feed_pcm`).**
|
||||||
|
> **Noise suppression shipped (RNNoise, vendored at `third_party/rnnoise/`)** — both send-side
|
||||||
|
> mic NR (`vc_set_input_noise_reduction`) and per-listener receive NR; client on/off toggles TBD.
|
||||||
|
> See [`PROGRESS.md`](PROGRESS.md).
|
||||||
|
|
||||||
VoiceCat = self-hosted native voice & text chat (TeamSpeak/Mumble-style). Plain TCP (control)
|
VoiceCat = self-hosted native voice & text chat (TeamSpeak/Mumble-style). Plain TCP (control)
|
||||||
+ UDP (media), no WebRTC, encrypted by default. A shared C++ core (`libvoicecat`) drives
|
+ UDP (media), no WebRTC, encrypted by default. A shared C++ core (`libvoicecat`) drives
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ cmake_minimum_required(VERSION 3.25)
|
|||||||
project(voicecat
|
project(voicecat
|
||||||
VERSION 0.0.1
|
VERSION 0.0.1
|
||||||
DESCRIPTION "Self-hosted native voice & text chat (see docs/)"
|
DESCRIPTION "Self-hosted native voice & text chat (see docs/)"
|
||||||
LANGUAGES CXX)
|
# C is needed for the vendored RNNoise noise-suppression lib (third_party/rnnoise).
|
||||||
|
LANGUAGES CXX C)
|
||||||
|
|
||||||
# On iOS, audio_engine.cpp includes miniaudio.h which pulls in AVFoundation Objective-C
|
# On iOS, audio_engine.cpp includes miniaudio.h which pulls in AVFoundation Objective-C
|
||||||
# headers. Those cannot be compiled as C++; we set audio_engine.cpp's LANGUAGE to OBJCXX
|
# headers. Those cannot be compiled as C++; we set audio_engine.cpp's LANGUAGE to OBJCXX
|
||||||
|
|||||||
20
PROGRESS.md
20
PROGRESS.md
@@ -10,6 +10,26 @@ up instantly. Newest status at the top.
|
|||||||
|
|
||||||
## ▶ Where we left off / next action
|
## ▶ Where we left off / next action
|
||||||
|
|
||||||
|
- **Done (2026-06-23):** **Remote-stream noise suppression — real backend (RNNoise).** The
|
||||||
|
two-sided NR plumbing (`RemoteStream::recv_ns` + `vc_set_remote_stream(... noise_reduction)`)
|
||||||
|
was wired but **inert** — `ApmProcessor::create()` returned a no-op passthrough, because the
|
||||||
|
originally-planned `webrtc-audio-processing` won't build on Windows/macOS. Replaced with
|
||||||
|
**RNNoise** (BSD-3 + CC0), vendored at `third_party/rnnoise/` (the vcpkg port is `!windows
|
||||||
|
!arm`), built as a standalone C static lib + `VOICECAT_HAS_NS`. One `RnnoiseProcessor`
|
||||||
|
(`core/src/audio/apm_processor.cpp`) now backs **both** NR paths:
|
||||||
|
- **Receive-side** (per-listener, per-`ssrc`): lit up automatically via the factory; gated to
|
||||||
|
mono streams (`audio_engine.cpp` ~L791).
|
||||||
|
- **Send-side** (mic, new): `vc_set_input_noise_reduction(client, enable)` ABI +
|
||||||
|
`vc_client::mic_ns_`, run before input gain/VAD in `on_capture_frame`. A stereo mic is
|
||||||
|
downmixed to mono **only when NR is on**; with NR off a stereo mic keeps full stereo.
|
||||||
|
- RNNoise is mono/48 kHz/480-sample; our clock is fixed 48 kHz and Opus frame sizes are all
|
||||||
|
multiples of 480, so no resampling. RT-safe: alloc at construction, lock-free in the callback.
|
||||||
|
- **Verify status:** `ctest --preset dev` green — **28/28** (new `noise_suppression` test:
|
||||||
|
feeds white noise through `ApmProcessor::create()`, measures **99.9%** RMS reduction). Build
|
||||||
|
clean on the `dev` MinGW preset. **Next (manual):** add the on/off toggles to the client UIs
|
||||||
|
(Windows Audio Settings dialog, macOS/iOS settings) calling the two ABIs; build `windows-client`
|
||||||
|
+ `apple-dev` presets to confirm RNNoise compiles under MinGW-DLL and arm64; two-client E2E.
|
||||||
|
|
||||||
- **Done (2026-06-23):** **Aux outgoing stream (mic + a second input device) — Windows + macOS.**
|
- **Done (2026-06-23):** **Aux outgoing stream (mic + a second input device) — Windows + macOS.**
|
||||||
Users can now transmit a second hardware input device (e.g. line-in / aux) alongside the mic, with
|
Users can now transmit a second hardware input device (e.g. line-in / aux) alongside the mic, with
|
||||||
its own device picker and volume, from Audio Settings. **No core/ABI/proto changes** — the aux is
|
its own device picker and volume, from Audio Settings. **No core/ABI/proto changes** — the aux is
|
||||||
|
|||||||
@@ -75,6 +75,38 @@ if(VOICECAT_USE_VCPKG_DEPS)
|
|||||||
|
|
||||||
target_compile_definitions(voicecat PUBLIC VOICECAT_HAS_OPUS VOICECAT_HAS_AUDIO)
|
target_compile_definitions(voicecat PUBLIC VOICECAT_HAS_OPUS VOICECAT_HAS_AUDIO)
|
||||||
|
|
||||||
|
# ── RNNoise — vendored noise-suppression DSP (third_party/rnnoise, BSD-3 + CC0). ──────────
|
||||||
|
# The real backend behind ApmProcessor (docs/voice.md §10-11). Built as a standalone C
|
||||||
|
# static lib with NO run-time CPU dispatch (RTCD off): portable scalar path on x86,
|
||||||
|
# auto-NEON on arm64. -DDISABLE_DEBUG_FLOAT selects the int8-quantized weights that match our
|
||||||
|
# shrunk model (third_party/README.md). The vcpkg port is !windows !arm, so we vendor it.
|
||||||
|
set(RNNOISE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../third_party/rnnoise)
|
||||||
|
add_library(rnnoise STATIC
|
||||||
|
${RNNOISE_DIR}/src/denoise.c
|
||||||
|
${RNNOISE_DIR}/src/rnn.c
|
||||||
|
${RNNOISE_DIR}/src/pitch.c
|
||||||
|
${RNNOISE_DIR}/src/kiss_fft.c
|
||||||
|
${RNNOISE_DIR}/src/celt_lpc.c
|
||||||
|
${RNNOISE_DIR}/src/nnet.c
|
||||||
|
${RNNOISE_DIR}/src/nnet_default.c
|
||||||
|
${RNNOISE_DIR}/src/parse_lpcnet_weights.c
|
||||||
|
${RNNOISE_DIR}/src/rnnoise_data.c
|
||||||
|
${RNNOISE_DIR}/src/rnnoise_tables.c)
|
||||||
|
target_include_directories(rnnoise
|
||||||
|
PUBLIC ${RNNOISE_DIR}/include
|
||||||
|
PRIVATE ${RNNOISE_DIR}/src)
|
||||||
|
target_compile_definitions(rnnoise PRIVATE DISABLE_DEBUG_FLOAT)
|
||||||
|
set_target_properties(rnnoise PROPERTIES
|
||||||
|
POSITION_INDEPENDENT_CODE ON # libvoicecat may be built SHARED (windows-client/apple)
|
||||||
|
C_VISIBILITY_PRESET hidden)
|
||||||
|
if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
|
||||||
|
# rnnoise is plain C; keep it compiling as C even though audio_engine.cpp is OBJCXX.
|
||||||
|
set_source_files_properties(${RNNOISE_DIR}/src/rnnoise_data.c PROPERTIES LANGUAGE C)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_link_libraries(voicecat PRIVATE rnnoise)
|
||||||
|
target_compile_definitions(voicecat PRIVATE VOICECAT_HAS_NS)
|
||||||
|
|
||||||
# On iOS, miniaudio's AVFoundation backend includes Objective-C headers (AVFoundation.h →
|
# On iOS, miniaudio's AVFoundation backend includes Objective-C headers (AVFoundation.h →
|
||||||
# Foundation.h). Compiling those as plain C++ fails; setting LANGUAGE OBJCXX for
|
# Foundation.h). Compiling those as plain C++ fails; setting LANGUAGE OBJCXX for
|
||||||
# audio_engine.cpp (the only file that includes miniaudio.h directly) fixes this.
|
# audio_engine.cpp (the only file that includes miniaudio.h directly) fixes this.
|
||||||
|
|||||||
@@ -392,6 +392,12 @@ VC_API vc_result vc_set_output_volume(vc_client* c, float gain);
|
|||||||
* always LOCAL — no protocol traffic. */
|
* always LOCAL — no protocol traffic. */
|
||||||
VC_API vc_result vc_set_input_gain(vc_client* c, float gain);
|
VC_API vc_result vc_set_input_gain(vc_client* c, float gain);
|
||||||
|
|
||||||
|
/* Send-side microphone noise suppression (RNNoise). Denoises captured MIC PCM before the input
|
||||||
|
* gain and the VAD/PTT gate, so everyone hears the cleaned signal (one pass for all listeners).
|
||||||
|
* enable != 0 turns it on. MIC stream only, mono only; always LOCAL — no protocol traffic.
|
||||||
|
* Independent of the per-listener receive-side NR in vc_set_remote_stream (docs/voice.md §10). */
|
||||||
|
VC_API vc_result vc_set_input_noise_reduction(vc_client* c, int enable);
|
||||||
|
|
||||||
/* Receive-side, per remote stream, all LOCAL (no protocol traffic) — docs/voice.md §10:
|
/* Receive-side, per remote stream, all LOCAL (no protocol traffic) — docs/voice.md §10:
|
||||||
* gain (0..) , mute, and listener-chosen noise reduction on a specific user's stream. */
|
* gain (0..) , mute, and listener-chosen noise reduction on a specific user's stream. */
|
||||||
VC_API vc_result vc_set_remote_stream(vc_client* c, uint32_t user_id, uint32_t stream_id,
|
VC_API vc_result vc_set_remote_stream(vc_client* c, uint32_t user_id, uint32_t stream_id,
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
#include "audio/apm_processor.h"
|
#include "audio/apm_processor.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
#ifdef VOICECAT_HAS_NS
|
||||||
|
#include "rnnoise.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace voicecat::audio {
|
namespace voicecat::audio {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -57,12 +62,55 @@ class EnergyVadProcessor final : public ApmProcessor {
|
|||||||
int64_t last_voice_ms_ = 0; // epoch start -> gate begins closed until first loud frame
|
int64_t last_voice_ms_ = 0; // epoch start -> gate begins closed until first loud frame
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef VOICECAT_HAS_NS
|
||||||
|
// ── RnnoiseProcessor ─────────────────────────────────────────────────────────
|
||||||
|
// Real noise suppression via vendored RNNoise (third_party/rnnoise; docs/voice.md §10-11).
|
||||||
|
// RNNoise is a mono, 48 kHz, fixed 480-sample (10 ms) speech denoiser; our engine clock is fixed
|
||||||
|
// at 48 kHz and every Opus frame size (480/960/1920/2880) is a multiple of 480, so we process
|
||||||
|
// whole 480-sample chunks with no resampling and no cross-call carry. Mono only — callers gate
|
||||||
|
// on a single channel (a stereo screen-audio share is never voice and isn't denoised).
|
||||||
|
//
|
||||||
|
// RT-safety (docs/architecture.md §3): the DenoiseState and the float scratch are allocated in the
|
||||||
|
// ctor; process_capture() does no allocation/locking. The state is owned per-stream (recv) or
|
||||||
|
// per-mic (send) so it persists across calls, which is exactly what RNNoise's overlap needs.
|
||||||
|
class RnnoiseProcessor final : public ApmProcessor {
|
||||||
|
public:
|
||||||
|
RnnoiseProcessor() : st_(rnnoise_create(nullptr)) {}
|
||||||
|
~RnnoiseProcessor() override {
|
||||||
|
if (st_) rnnoise_destroy(st_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_render(const int16_t*, int, int) override {} // NS needs no AEC reference
|
||||||
|
|
||||||
|
bool process_capture(int16_t* pcm, int samples, int sample_rate) override {
|
||||||
|
// RNNoise is 48 kHz only; anything else passes through untouched (our clock is 48 kHz, so
|
||||||
|
// this guard never trips in practice — it's just a correctness backstop).
|
||||||
|
if (!st_ || sample_rate != 48000) return true;
|
||||||
|
for (int off = 0; off + kFrame <= samples; off += kFrame) {
|
||||||
|
for (int i = 0; i < kFrame; ++i) in_[i] = static_cast<float>(pcm[off + i]);
|
||||||
|
rnnoise_process_frame(st_, out_, in_);
|
||||||
|
for (int i = 0; i < kFrame; ++i) {
|
||||||
|
int32_t v = static_cast<int32_t>(std::lround(out_[i]));
|
||||||
|
pcm[off + i] = static_cast<int16_t>(std::clamp(v, -32768, 32767));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true; // NS doesn't gate; the send path's VAD stays a separate stage
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr int kFrame = 480; // rnnoise_get_frame_size()
|
||||||
|
DenoiseState* st_;
|
||||||
|
float in_[kFrame];
|
||||||
|
float out_[kFrame];
|
||||||
|
};
|
||||||
|
#endif // VOICECAT_HAS_NS
|
||||||
|
|
||||||
std::unique_ptr<ApmProcessor> ApmProcessor::create() {
|
std::unique_ptr<ApmProcessor> ApmProcessor::create() {
|
||||||
#ifdef VOICECAT_HAS_APM
|
#ifdef VOICECAT_HAS_NS
|
||||||
// TODO: return std::make_unique<WebrtcApmProcessor>(); — see create_vad()'s doc comment for
|
return std::make_unique<RnnoiseProcessor>();
|
||||||
// why this isn't wired up yet (no working Windows/MSVC build upstream).
|
#else
|
||||||
#endif
|
|
||||||
return std::make_unique<ApmPassthrough>();
|
return std::make_unique<ApmPassthrough>();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<ApmProcessor> ApmProcessor::create_vad(float rms_threshold,
|
std::unique_ptr<ApmProcessor> ApmProcessor::create_vad(float rms_threshold,
|
||||||
|
|||||||
@@ -28,10 +28,12 @@ class ApmProcessor {
|
|||||||
// Safe to call from any thread — EnergyVadProcessor stores it atomically.
|
// Safe to call from any thread — EnergyVadProcessor stores it atomically.
|
||||||
virtual void set_threshold(float) {}
|
virtual void set_threshold(float) {}
|
||||||
|
|
||||||
// Factory: returns a real APM if VOICECAT_HAS_APM is defined, else a passthrough. Used for
|
// Factory for the noise-suppression backend (docs/voice.md §10-11): a real RNNoise denoiser
|
||||||
// recv-side per-stream noise reduction (docs/voice.md §10) — gating doesn't apply there, so
|
// when VOICECAT_HAS_NS is defined (third_party/rnnoise), else a no-op passthrough. Used for
|
||||||
// this stays a passthrough until a real APM/NS backend exists (still inert; see
|
// BOTH recv-side per-stream NR (RemoteStream::recv_ns) and send-side mic NR (vc_client's
|
||||||
// PROGRESS.md). Do not use this for the send-side VAD gate — see create_vad() below.
|
// mic_ns_). The RNNoise backend is mono/48 kHz only, so callers gate it on a single channel.
|
||||||
|
// NS never gates (process_capture always returns true) — the send-side VAD is separate, see
|
||||||
|
// create_vad() below.
|
||||||
static std::unique_ptr<ApmProcessor> create();
|
static std::unique_ptr<ApmProcessor> create();
|
||||||
|
|
||||||
// Factory for the send-side input gate (docs/voice.md §11): a lightweight, dependency-free
|
// Factory for the send-side input gate (docs/voice.md §11): a lightweight, dependency-free
|
||||||
|
|||||||
@@ -788,7 +788,9 @@ void AudioEngine::on_playback(int16_t* out, ma_uint32 frames) {
|
|||||||
|
|
||||||
// `n` is samples-per-channel (matches the frame_samples convention used by
|
// `n` is samples-per-channel (matches the frame_samples convention used by
|
||||||
// OpusEncoder::encode elsewhere in the codebase).
|
// OpusEncoder::encode elsewhere in the codebase).
|
||||||
if (stream.recv_ns)
|
// RNNoise is mono-only; a stereo stream (screen-audio share) is never voice, so skip
|
||||||
|
// NR there rather than denoise a garbled deinterleave (docs/voice.md §10).
|
||||||
|
if (stream.recv_ns && dec_channels == 1)
|
||||||
stream.recv_ns->process_capture(stream.decode_scratch.data(), n,
|
stream.recv_ns->process_capture(stream.decode_scratch.data(), n,
|
||||||
static_cast<int>(params_.sample_rate));
|
static_cast<int>(params_.sample_rate));
|
||||||
|
|
||||||
|
|||||||
@@ -1009,6 +1009,24 @@ void vc_client::on_capture_frame(int kind, const int16_t* pcm, int samples, int
|
|||||||
(self_mic_muted_.load(std::memory_order_acquire) ||
|
(self_mic_muted_.load(std::memory_order_acquire) ||
|
||||||
server_muted_.load(std::memory_order_acquire))) return;
|
server_muted_.load(std::memory_order_acquire))) return;
|
||||||
|
|
||||||
|
// Send-side mic noise suppression (vc_set_input_noise_reduction) — MIC only. Runs first, on
|
||||||
|
// the raw mic, so the gain boost and the VAD gate below both see the cleaned signal. mic_ns_
|
||||||
|
// exists for the lifetime of the MIC stream; the atomic flip gates it without touching the
|
||||||
|
// pointer on this RT callback. RNNoise is a mono 48 kHz denoiser, so a stereo mic is downmixed
|
||||||
|
// to mono IN PLACE here — but only when NS is enabled. With NS off this block is skipped
|
||||||
|
// entirely, so a stereo mic keeps full stereo: we never collapse mic quality unless asked.
|
||||||
|
if (kind == static_cast<int>(VC_STREAM_MIC) && mic_ns_ &&
|
||||||
|
input_noise_reduction_.load(std::memory_order_relaxed)) {
|
||||||
|
int16_t* w = const_cast<int16_t*>(pcm);
|
||||||
|
if (channels == 2) {
|
||||||
|
for (int i = 0; i < samples; ++i)
|
||||||
|
w[i] = static_cast<int16_t>(
|
||||||
|
(static_cast<int32_t>(w[2 * i]) + static_cast<int32_t>(w[2 * i + 1])) / 2);
|
||||||
|
channels = 1; // rest of the pipeline (gain, gate, encode) now sees a mono frame
|
||||||
|
}
|
||||||
|
if (channels == 1) mic_ns_->process_capture(w, samples, 48000);
|
||||||
|
}
|
||||||
|
|
||||||
// Send-side mic input gain (vc_set_input_gain) — MIC only. Applied in place before the gate
|
// Send-side mic input gain (vc_set_input_gain) — MIC only. Applied in place before the gate
|
||||||
// so a boosted quiet mic also helps cross the VAD threshold. EnergyVadProcessor never writes
|
// so a boosted quiet mic also helps cross the VAD threshold. EnergyVadProcessor never writes
|
||||||
// through its pointer, so the const_cast (same as the VAD path below) is safe; no allocation.
|
// through its pointer, so the const_cast (same as the VAD path below) is safe; no allocation.
|
||||||
@@ -1329,6 +1347,11 @@ void vc_client::handle_stream_announce_result(uint64_t req_id,
|
|||||||
mic_vad_ = voicecat::audio::ApmProcessor::create_vad(
|
mic_vad_ = voicecat::audio::ApmProcessor::create_vad(
|
||||||
vad_threshold_.load(std::memory_order_relaxed));
|
vad_threshold_.load(std::memory_order_relaxed));
|
||||||
}
|
}
|
||||||
|
// Mic noise suppressor, built once here (not on the RT capture callback). Always created
|
||||||
|
// so the toggle is a pure atomic flip — see client.h's comment on mic_ns_.
|
||||||
|
if (kind == static_cast<int>(VC_STREAM_MIC) && !mic_ns_) {
|
||||||
|
mic_ns_ = voicecat::audio::ApmProcessor::create();
|
||||||
|
}
|
||||||
|
|
||||||
// SCREEN_AUDIO loopback opens the WASAPI device in the channel's mode: stereo capture
|
// SCREEN_AUDIO loopback opens the WASAPI device in the channel's mode: stereo capture
|
||||||
// when the channel is stereo (real L/R, no downmix), mono otherwise. Captured under
|
// when the channel is stereo (real L/R, no downmix), mono otherwise. Captured under
|
||||||
@@ -1473,6 +1496,13 @@ vc_result vc_client::set_input_gain(float gain) {
|
|||||||
return VC_OK;
|
return VC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vc_result vc_client::set_input_noise_reduction(bool enable) {
|
||||||
|
// Pure local toggle (like set_input_gain): mic_ns_ is created with the MIC stream, this only
|
||||||
|
// flips whether the capture callback runs it. Safe to call before a MIC stream exists.
|
||||||
|
input_noise_reduction_.store(enable, std::memory_order_relaxed);
|
||||||
|
return VC_OK;
|
||||||
|
}
|
||||||
|
|
||||||
vc_result vc_client::set_remote_stream(uint32_t user_id, uint32_t stream_id, float gain,
|
vc_result vc_client::set_remote_stream(uint32_t user_id, uint32_t stream_id, float gain,
|
||||||
bool muted, bool noise_reduction) {
|
bool muted, bool noise_reduction) {
|
||||||
if (state_net_.load(std::memory_order_acquire) != VC_STATE_CONNECTED) return VC_ERR_NOT_CONNECTED;
|
if (state_net_.load(std::memory_order_acquire) != VC_STATE_CONNECTED) return VC_ERR_NOT_CONNECTED;
|
||||||
@@ -1990,6 +2020,7 @@ vc_result vc_client::set_capture_channels(uint32_t, uint32_t) { return VC_ERR_NO
|
|||||||
vc_result vc_client::set_input_mode(vc_input_mode) { return VC_ERR_NOT_IMPLEMENTED; }
|
vc_result vc_client::set_input_mode(vc_input_mode) { return VC_ERR_NOT_IMPLEMENTED; }
|
||||||
vc_result vc_client::set_vad_threshold(float) { return VC_ERR_NOT_IMPLEMENTED; }
|
vc_result vc_client::set_vad_threshold(float) { return VC_ERR_NOT_IMPLEMENTED; }
|
||||||
vc_result vc_client::set_input_gain(float) { return VC_ERR_NOT_IMPLEMENTED; }
|
vc_result vc_client::set_input_gain(float) { return VC_ERR_NOT_IMPLEMENTED; }
|
||||||
|
vc_result vc_client::set_input_noise_reduction(bool) { return VC_ERR_NOT_IMPLEMENTED; }
|
||||||
vc_result vc_client::set_push_to_talk(bool) { return VC_ERR_NOT_IMPLEMENTED; }
|
vc_result vc_client::set_push_to_talk(bool) { return VC_ERR_NOT_IMPLEMENTED; }
|
||||||
vc_result vc_client::set_self_mute(bool, bool) { return VC_ERR_NOT_IMPLEMENTED; }
|
vc_result vc_client::set_self_mute(bool, bool) { return VC_ERR_NOT_IMPLEMENTED; }
|
||||||
vc_result vc_client::set_remote_stream(uint32_t, uint32_t, float, bool, bool) {
|
vc_result vc_client::set_remote_stream(uint32_t, uint32_t, float, bool, bool) {
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ struct vc_client {
|
|||||||
vc_result set_self_mute(bool mic_muted, bool deafened);
|
vc_result set_self_mute(bool mic_muted, bool deafened);
|
||||||
vc_result set_output_volume(float gain);
|
vc_result set_output_volume(float gain);
|
||||||
vc_result set_input_gain(float gain);
|
vc_result set_input_gain(float gain);
|
||||||
|
vc_result set_input_noise_reduction(bool enable);
|
||||||
vc_result set_remote_stream(uint32_t user_id, uint32_t stream_id, float gain, bool muted,
|
vc_result set_remote_stream(uint32_t user_id, uint32_t stream_id, float gain, bool muted,
|
||||||
bool noise_reduction);
|
bool noise_reduction);
|
||||||
vc_result get_remote_stream(uint32_t user_id, uint32_t stream_id,
|
vc_result get_remote_stream(uint32_t user_id, uint32_t stream_id,
|
||||||
@@ -313,12 +314,17 @@ struct vc_client {
|
|||||||
std::atomic<bool> ptt_active_{false};
|
std::atomic<bool> ptt_active_{false};
|
||||||
std::atomic<float> vad_threshold_{0.025f}; // remembered across mode switches
|
std::atomic<float> vad_threshold_{0.025f}; // remembered across mode switches
|
||||||
std::atomic<float> input_gain_{1.0f}; // send-side MIC gain (vc_set_input_gain)
|
std::atomic<float> input_gain_{1.0f}; // send-side MIC gain (vc_set_input_gain)
|
||||||
|
std::atomic<bool> input_noise_reduction_{false}; // send-side MIC NS (vc_set_input_noise_reduction)
|
||||||
|
|
||||||
// External-playback mode (iOS VPIO): when true, ensure_audio_running() configures the
|
// External-playback mode (iOS VPIO): when true, ensure_audio_running() configures the
|
||||||
// AudioEngine to skip its hardware playback device and drive the mixer on a timer instead,
|
// AudioEngine to skip its hardware playback device and drive the mixer on a timer instead,
|
||||||
// delivering the final mix to the mixed-output sink. Set via vc_set_external_playback.
|
// delivering the final mix to the mixed-output sink. Set via vc_set_external_playback.
|
||||||
std::atomic<bool> external_playback_{false};
|
std::atomic<bool> external_playback_{false};
|
||||||
std::unique_ptr<voicecat::audio::ApmProcessor> mic_vad_;
|
std::unique_ptr<voicecat::audio::ApmProcessor> mic_vad_;
|
||||||
|
// Send-side mic noise suppressor (RNNoise). Constructed once with the MIC stream alongside
|
||||||
|
// mic_vad_ (off the RT capture callback); toggling only flips input_noise_reduction_, so the
|
||||||
|
// capture callback never allocates or races this pointer.
|
||||||
|
std::unique_ptr<voicecat::audio::ApmProcessor> mic_ns_;
|
||||||
|
|
||||||
// teardown_voice() is called both from run_io()'s own cleanup (on the io_thread_, when
|
// teardown_voice() is called both from run_io()'s own cleanup (on the io_thread_, when
|
||||||
// the read loop exits) and from disconnect() (on the caller's thread) -- without
|
// the read loop exits) and from disconnect() (on the caller's thread) -- without
|
||||||
|
|||||||
@@ -127,6 +127,11 @@ vc_result vc_set_input_gain(vc_client* c, float gain) {
|
|||||||
return c->set_input_gain(gain);
|
return c->set_input_gain(gain);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vc_result vc_set_input_noise_reduction(vc_client* c, int enable) {
|
||||||
|
if (c == nullptr) return VC_ERR_INVALID_ARG;
|
||||||
|
return c->set_input_noise_reduction(enable != 0);
|
||||||
|
}
|
||||||
|
|
||||||
vc_result vc_set_remote_stream(vc_client* c, uint32_t user_id, uint32_t stream_id, float gain,
|
vc_result vc_set_remote_stream(vc_client* c, uint32_t user_id, uint32_t stream_id, float gain,
|
||||||
int muted, int noise_reduction) {
|
int muted, int noise_reduction) {
|
||||||
if (c == nullptr) return VC_ERR_INVALID_ARG;
|
if (c == nullptr) return VC_ERR_INVALID_ARG;
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ Concrete library choices with versions and rationale. Everything in the **core**
|
|||||||
| Crypto primitives + password hashing + media AEAD | **libsodium** | 1.0.20 | **ISC.** Argon2id (`crypto_pwhash`), ChaCha20-Poly1305 (per-frame media encryption), Ed25519 server identity, X25519, CSPRNG. Audited, hard to misuse. |
|
| Crypto primitives + password hashing + media AEAD | **libsodium** | 1.0.20 | **ISC.** Argon2id (`crypto_pwhash`), ChaCha20-Poly1305 (per-frame media encryption), Ed25519 server identity, X25519, CSPRNG. Audited, hard to misuse. |
|
||||||
| Audio codec | **libopus** | **1.6** (2025-12) | Per-channel mono/stereo, bitrate, frame size; in-band FEC, DTX, PLC, and optional **DRED** deep redundancy; Opus HD/96 kHz available. The whole reason the design is codec-flexible. |
|
| Audio codec | **libopus** | **1.6** (2025-12) | Per-channel mono/stereo, bitrate, frame size; in-band FEC, DTX, PLC, and optional **DRED** deep redundancy; Opus HD/96 kHz available. The whole reason the design is codec-flexible. |
|
||||||
| Audio capture/playback | **miniaudio** | 0.11.x | Single-header, public-domain, backends for **WASAPI / CoreAudio / ALSA / PulseAudio**. One real-time abstraction across all desktop targets; keeps the RT path identical. |
|
| Audio capture/playback | **miniaudio** | 0.11.x | Single-header, public-domain, backends for **WASAPI / CoreAudio / ALSA / PulseAudio**. One real-time abstraction across all desktop targets; keeps the RT path identical. |
|
||||||
| Audio DSP — AEC/NS/AGC/VAD | **webrtc-audio-processing** (APM) — **planned, not built** | 1.x (standalone APM) | **BSD-3**, but has no working Windows/MSVC build upstream (GCC-only Meson, MinGW support unfinished, hard `abseil-cpp` dep — see roadmap.md §2). v1 ships a lightweight, dependency-free energy/RMS VAD instead (`core/src/audio/apm_processor.cpp`); there is **no AEC, NS, or AGC implementation at all** yet. Real APM stays a tracked future swap behind the same `ApmProcessor` interface. |
|
| Audio DSP — noise suppression (NS) | **RNNoise** (vendored, `third_party/rnnoise/`) | xiph @ `70f1d25` (2026-06) | **BSD-3-Clause + CC0-1.0** (model). Hybrid DSP/RNN speech denoiser, mono/48 kHz, ~60× real time, no deps. The shipped NS backend behind `ApmProcessor` (`RnnoiseProcessor`), used by both send-side mic NR (`vc_set_input_noise_reduction`) and per-listener receive NR (`vc_set_remote_stream`). Vendored (not vcpkg) because the vcpkg port is `!windows !arm`. See [voice.md](voice.md) §10. |
|
||||||
|
| Audio DSP — AEC/AGC/VAD | **webrtc-audio-processing** (APM) — **planned, not built** | 1.x (standalone APM) | **BSD-3**, but has no working Windows/MSVC build upstream (GCC-only Meson, MinGW support unfinished, hard `abseil-cpp` dep — see roadmap.md §2). v1 ships a lightweight, dependency-free energy/RMS VAD (`EnergyVadProcessor`, `core/src/audio/apm_processor.cpp`); **NS now exists via RNNoise (row above)**, but there is still **no AEC or AGC** (iOS gets AEC/NS/AGC natively from VPIO). Real APM stays a tracked future swap behind the same `ApmProcessor` interface. |
|
||||||
| Resampling + jitter ref | **speexdsp** | 1.2.x | BSD. Resampler for non-48 kHz devices; lightweight jitter-buffer reference. (No longer the NS/AGC/VAD source — APM replaces it.) |
|
| Resampling + jitter ref | **speexdsp** | 1.2.x | BSD. Resampler for non-48 kHz devices; lightweight jitter-buffer reference. (No longer the NS/AGC/VAD source — APM replaces it.) |
|
||||||
| Control serialization | **Protocol Buffers** (protobuf-lite) | 5.x (proto3) | Codegen for C++/C#/Swift; additive, forward/backward compatible; `oneof` envelopes. `nanopb` is a fallback if footprint matters. |
|
| Control serialization | **Protocol Buffers** (protobuf-lite) | 5.x (proto3) | Codegen for C++/C#/Swift; additive, forward/backward compatible; `oneof` envelopes. `nanopb` is a fallback if footprint matters. |
|
||||||
| Server persistence | **SQLite** | 3.4x | Accounts, channels, bans, config. Zero-admin, single file, ships everywhere. |
|
| Server persistence | **SQLite** | 3.4x | Accounts, channels, bans, config. Zero-admin, single file, ships everywhere. |
|
||||||
@@ -74,7 +75,9 @@ public-domain:
|
|||||||
|
|
||||||
- **mbedTLS** — Apache-2.0 ✅ · **libsodium** — ISC ✅ · **libopus** — BSD ✅ ·
|
- **mbedTLS** — Apache-2.0 ✅ · **libsodium** — ISC ✅ · **libopus** — BSD ✅ ·
|
||||||
**miniaudio** — public domain / MIT-0 ✅ · **protobuf** — BSD ✅ ·
|
**miniaudio** — public domain / MIT-0 ✅ · **protobuf** — BSD ✅ ·
|
||||||
**SQLite** — public domain ✅ · **Asio** (standalone) — Boost ✅ · **spdlog** — MIT ✅.
|
**SQLite** — public domain ✅ · **Asio** (standalone) — Boost ✅ · **spdlog** — MIT ✅ ·
|
||||||
|
**RNNoise** — BSD-3-Clause (code) + CC0-1.0 (model) ✅, vendored in `third_party/rnnoise/`
|
||||||
|
(not vcpkg — the port is `!windows !arm`; see [`third_party/README.md`](../third_party/README.md)).
|
||||||
**webrtc-audio-processing** would be BSD-3 ✅ if/when it's actually built in (see §1) —
|
**webrtc-audio-processing** would be BSD-3 ✅ if/when it's actually built in (see §1) —
|
||||||
not a live dependency today, so not part of the resolved vcpkg graph the license scanner
|
not a live dependency today, so not part of the resolved vcpkg graph the license scanner
|
||||||
below checks.
|
below checks.
|
||||||
|
|||||||
@@ -287,17 +287,37 @@ Each receiver keeps an **adaptive jitter buffer per ssrc** with **bounded-depth
|
|||||||
Noise reduction can be applied **at the sender, at the listener, or both** — they are
|
Noise reduction can be applied **at the sender, at the listener, or both** — they are
|
||||||
independent.
|
independent.
|
||||||
|
|
||||||
- **Sender-side** (the talker's choice): the publishing client runs APM noise suppression on
|
- **Sender-side** (the talker's choice): the publishing client runs noise suppression on its
|
||||||
its mic before encoding, controlled by that user's own settings. This cleans the signal for
|
mic before the input gain and the VAD/PTT gate, controlled by that user's own settings
|
||||||
*everyone* and saves bitrate.
|
(`vc_set_input_noise_reduction`). This cleans the signal for *everyone* in one pass and helps
|
||||||
|
bitrate/VAD. MIC stream only.
|
||||||
- **Listener-side, per user** (the listener's choice): on the receive path, *after* decoding
|
- **Listener-side, per user** (the listener's choice): on the receive path, *after* decoding
|
||||||
each stream and *before* mixing, the listener can enable an **additional** NS pass on a
|
each stream and *before* mixing, the listener can enable an **additional** NS pass on a
|
||||||
**specific** sender's stream. So even if Alex chose not to denoise his mic, Sam can locally
|
**specific** sender's stream (`vc_set_remote_stream(..., noise_reduction)`). So even if Alex
|
||||||
suppress Alex's background noise without affecting how anyone else hears Alex.
|
chose not to denoise his mic, Sam can locally suppress Alex's background noise without
|
||||||
|
affecting how anyone else hears Alex.
|
||||||
|
|
||||||
Implementation: a per-`ssrc` APM NS instance on the receive path, instantiated lazily only
|
**Backend: RNNoise** (vendored in [`third_party/rnnoise/`](../third_party/rnnoise), BSD-3 + CC0).
|
||||||
for streams the listener has flagged. State lives entirely on the listener's machine; toggling
|
The original plan was WebRTC's APM, but `webrtc-audio-processing` has no working Windows/MSVC
|
||||||
it is a local UI action with **no protocol message** and no effect on other listeners. Because
|
build (see §8). RNNoise is a small, dependency-free C library — a hybrid DSP/RNN speech denoiser
|
||||||
|
that runs ~60× faster than real time. Both NR paths share one `ApmProcessor` implementation
|
||||||
|
(`RnnoiseProcessor`, `core/src/audio/apm_processor.cpp`), selected by `ApmProcessor::create()`
|
||||||
|
when the core is built with `VOICECAT_HAS_NS` (a no-op `ApmPassthrough` otherwise). Allocation
|
||||||
|
happens at construction; `process_capture()` runs lock-free on the RT thread (architecture.md §3).
|
||||||
|
|
||||||
|
RNNoise is a **mono, 48 kHz, 480-sample (10 ms)** denoiser. Our engine clock is fixed at 48 kHz
|
||||||
|
and every Opus frame size (480/960/1920/2880) is a multiple of 480, so frames are processed as
|
||||||
|
whole 480-sample chunks with no resampling. Because it's mono-only:
|
||||||
|
- **Send-side:** a stereo mic is downmixed to mono **only when NR is enabled** — with NR off a
|
||||||
|
stereo mic keeps full stereo (we never collapse mic quality unless asked).
|
||||||
|
- **Receive-side:** NR is skipped on stereo streams (a stereo stream is a screen-audio share,
|
||||||
|
not voice).
|
||||||
|
|
||||||
|
Implementation: a per-`ssrc` NS instance (`RemoteStream::recv_ns`) on the receive path,
|
||||||
|
instantiated lazily only for streams the listener has flagged; the send-side instance
|
||||||
|
(`vc_client::mic_ns_`) is built once with the MIC stream and gated by an atomic flag so toggling
|
||||||
|
never allocates on the capture callback. State lives entirely on the local machine; toggling
|
||||||
|
either is a local UI action with **no protocol message** and no effect on other users. Because
|
||||||
each receive stream is decoded independently before the mixer (voice.md §1), per-user receive
|
each receive stream is decoded independently before the mixer (voice.md §1), per-user receive
|
||||||
NS is a clean drop-in on that per-stream stage.
|
NS is a clean drop-in on that per-stream stage.
|
||||||
|
|
||||||
|
|||||||
@@ -229,4 +229,12 @@ if(VOICECAT_USE_VCPKG_DEPS)
|
|||||||
target_include_directories(test_channel_samplerate PRIVATE ${VC_TEST_INTERNAL_INCLUDES})
|
target_include_directories(test_channel_samplerate PRIVATE ${VC_TEST_INTERNAL_INCLUDES})
|
||||||
add_test(NAME channel_samplerate COMMAND test_channel_samplerate)
|
add_test(NAME channel_samplerate COMMAND test_channel_samplerate)
|
||||||
set_tests_properties(channel_samplerate PROPERTIES TIMEOUT 90)
|
set_tests_properties(channel_samplerate PROPERTIES TIMEOUT 90)
|
||||||
|
|
||||||
|
# Noise suppression: the RNNoise backend behind ApmProcessor actually denoises (docs/voice.md
|
||||||
|
# §10-11). Links core only; reaches the internal audio/ headers for ApmProcessor::create().
|
||||||
|
add_executable(test_noise_suppression test_noise_suppression.cpp)
|
||||||
|
target_link_libraries(test_noise_suppression PRIVATE voicecat::voicecat)
|
||||||
|
target_compile_features(test_noise_suppression PRIVATE cxx_std_20)
|
||||||
|
target_include_directories(test_noise_suppression PRIVATE ${VC_TEST_INTERNAL_INCLUDES})
|
||||||
|
add_test(NAME noise_suppression COMMAND test_noise_suppression)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
100
tests/test_noise_suppression.cpp
Normal file
100
tests/test_noise_suppression.cpp
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* test_noise_suppression — the RNNoise backend behind ApmProcessor actually denoises.
|
||||||
|
*
|
||||||
|
* This is the behavior exit-criterion for the noise-suppression feature (docs/voice.md §10-11):
|
||||||
|
* a real DSP backend, not the old inert passthrough. ApmProcessor::create() returns the RNNoise
|
||||||
|
* processor when the core is built with VOICECAT_HAS_NS (the dev/release presets). We feed it
|
||||||
|
* mono 48 kHz white noise in 20 ms (960-sample) frames — exercising the internal 480-sample
|
||||||
|
* chunking — and assert the output noise floor collapses while values stay finite/in-range.
|
||||||
|
*
|
||||||
|
* Registered only under VOICECAT_USE_VCPKG_DEPS, where VOICECAT_HAS_NS is defined, so a large
|
||||||
|
* reduction is expected; a passthrough build would (correctly) fail this test.
|
||||||
|
*/
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "audio/apm_processor.h"
|
||||||
|
|
||||||
|
namespace vca = voicecat::audio;
|
||||||
|
|
||||||
|
static int g_failures = 0;
|
||||||
|
|
||||||
|
#define CHECK(cond) \
|
||||||
|
do { \
|
||||||
|
if (!(cond)) { \
|
||||||
|
std::printf("FAIL [%s:%d]: %s\n", __FILE__, __LINE__, #cond); \
|
||||||
|
++g_failures; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
static constexpr int kFrameSamples = 960; // 20 ms @ 48 kHz (two RNNoise 480-sample frames)
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
auto ns = vca::ApmProcessor::create();
|
||||||
|
CHECK(ns != nullptr);
|
||||||
|
if (!ns) return 1;
|
||||||
|
|
||||||
|
// Deterministic white noise (xorshift) at ~int16/10 amplitude, processed frame by frame.
|
||||||
|
uint32_t rng = 0x12345678u;
|
||||||
|
auto next_noise = [&]() -> int16_t {
|
||||||
|
rng ^= rng << 13;
|
||||||
|
rng ^= rng >> 17;
|
||||||
|
rng ^= rng << 5;
|
||||||
|
// map to roughly [-3000, 3000]
|
||||||
|
return static_cast<int16_t>((static_cast<int32_t>(rng % 6001)) - 3000);
|
||||||
|
};
|
||||||
|
|
||||||
|
const int kFrames = 200;
|
||||||
|
const int kWarmup = 60; // let RNNoise's recurrent state settle before measuring
|
||||||
|
double in_sumsq = 0.0, out_sumsq = 0.0;
|
||||||
|
long measured = 0;
|
||||||
|
std::vector<int16_t> frame(kFrameSamples);
|
||||||
|
|
||||||
|
for (int f = 0; f < kFrames; ++f) {
|
||||||
|
double frame_in_sq = 0.0;
|
||||||
|
for (int i = 0; i < kFrameSamples; ++i) {
|
||||||
|
frame[i] = next_noise();
|
||||||
|
frame_in_sq += static_cast<double>(frame[i]) * frame[i];
|
||||||
|
}
|
||||||
|
bool gate = ns->process_capture(frame.data(), kFrameSamples, 48000);
|
||||||
|
CHECK(gate); // NS never gates — always passes the frame on
|
||||||
|
|
||||||
|
if (f >= kWarmup) {
|
||||||
|
in_sumsq += frame_in_sq;
|
||||||
|
for (int i = 0; i < kFrameSamples; ++i) {
|
||||||
|
// Output must stay finite and within int16 range (clamping correctness).
|
||||||
|
CHECK(frame[i] >= -32768 && frame[i] <= 32767);
|
||||||
|
out_sumsq += static_cast<double>(frame[i]) * frame[i];
|
||||||
|
}
|
||||||
|
measured += kFrameSamples;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK(measured > 0);
|
||||||
|
double in_rms = std::sqrt(in_sumsq / measured);
|
||||||
|
double out_rms = std::sqrt(out_sumsq / measured);
|
||||||
|
double reduction = (in_rms > 0.0) ? (1.0 - out_rms / in_rms) : 0.0;
|
||||||
|
std::printf("noise-only: in_rms=%.1f out_rms=%.1f reduction=%.1f%%\n", in_rms, out_rms,
|
||||||
|
100.0 * reduction);
|
||||||
|
|
||||||
|
// RNNoise drops pure noise by ~99%; require a large, unambiguous reduction so a passthrough
|
||||||
|
// (no real backend) is caught. The threshold is deliberately conservative vs. the ~99% seen.
|
||||||
|
CHECK(reduction > 0.80);
|
||||||
|
|
||||||
|
// A 48-kHz guard miss must pass audio through untouched (our clock is always 48 kHz, but the
|
||||||
|
// backstop matters): feed a non-48k sample-rate and confirm the buffer is unchanged.
|
||||||
|
std::vector<int16_t> probe(kFrameSamples);
|
||||||
|
for (int i = 0; i < kFrameSamples; ++i) probe[i] = next_noise();
|
||||||
|
std::vector<int16_t> probe_copy = probe;
|
||||||
|
ns->process_capture(probe.data(), kFrameSamples, 16000);
|
||||||
|
CHECK(probe == probe_copy);
|
||||||
|
|
||||||
|
if (g_failures == 0) {
|
||||||
|
std::printf("noise_suppression: OK\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
std::printf("noise_suppression: %d failure(s)\n", g_failures);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
34
third_party/README.md
vendored
Normal file
34
third_party/README.md
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# third_party/ — vendored dependencies
|
||||||
|
|
||||||
|
Dependencies that are **not** consumed through vcpkg live here, copied verbatim into the tree.
|
||||||
|
Everything here is permissively licensed (no GPL/LGPL) per the house rule in
|
||||||
|
[`docs/tech-stack.md`](../docs/tech-stack.md) §5.
|
||||||
|
|
||||||
|
## rnnoise/
|
||||||
|
|
||||||
|
Real-time speech **noise suppression** (the DSP backend behind `ApmProcessor` —
|
||||||
|
see [`docs/voice.md`](../docs/voice.md) §10–11). Used by the receive-side per-stream NR
|
||||||
|
(`RemoteStream::recv_ns`) and the send-side mic NR (`vc_client::mic_ns_`).
|
||||||
|
|
||||||
|
- **Upstream:** https://github.com/xiph/rnnoise
|
||||||
|
- **Vendored at commit:** `70f1d256acd4b34a572f999a05c87bf00b67730d`
|
||||||
|
- **License:** BSD-3-Clause (code, see `rnnoise/COPYING`) + CC0-1.0 (model weights).
|
||||||
|
- **Why vendored, not vcpkg:** the vcpkg `rnnoise` port is marked `!windows !arm`, i.e.
|
||||||
|
unavailable on our primary targets (Windows MinGW, Apple Silicon, iOS). RNNoise is small,
|
||||||
|
self-contained C99 with no dependencies, so we vendor it directly.
|
||||||
|
|
||||||
|
### What was copied / changed
|
||||||
|
- Only the **library** sources + headers (`src/*.c`, `src/*.h`, `src/x86/*.h`, `include/`).
|
||||||
|
The training/feature-dump tools (`dump_features.c`, `write_weights.c`, the `src/x86/*.c`
|
||||||
|
RTCD kernels), build scaffolding (autotools, Meson) and `torch/` `training/` dirs are omitted.
|
||||||
|
- `src/rnnoise_data.c` is the **shrunk** model: upstream's `scripts/shrink_model.sh` strips the
|
||||||
|
`#ifndef DISABLE_DEBUG_FLOAT` float-weight duplicates, taking the default model from ~78 MB to
|
||||||
|
~11.7 MB. We build with `-DDISABLE_DEBUG_FLOAT` so only the int8-quantized weights are used —
|
||||||
|
this is exactly how upstream's default (non-debug) build behaves. The model is the built-in
|
||||||
|
default loaded by `rnnoise_create(NULL)`; there is **no runtime model file**.
|
||||||
|
|
||||||
|
### Build
|
||||||
|
Built as a standalone static lib `rnnoise` in [`core/CMakeLists.txt`](../core/CMakeLists.txt)
|
||||||
|
(no RTCD; portable scalar path on x86, NEON on arm64), and linked into `libvoicecat` which
|
||||||
|
defines `VOICECAT_HAS_NS`. To refresh the model, re-run upstream `autogen.sh`/`download_model.sh`
|
||||||
|
+ `scripts/shrink_model.sh` and re-copy `src/rnnoise_data.{c,h}`.
|
||||||
1
third_party/rnnoise/AUTHORS
vendored
Normal file
1
third_party/rnnoise/AUTHORS
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Jean-Marc Valin <jmvalin@jmvalin.ca>
|
||||||
32
third_party/rnnoise/COPYING
vendored
Normal file
32
third_party/rnnoise/COPYING
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
Copyright (c) 2007-2017, 2024 Jean-Marc Valin
|
||||||
|
Copyright (c) 2023 Amazon
|
||||||
|
Copyright (c) 2017, Mozilla
|
||||||
|
Copyright (c) 2005-2017, Xiph.Org Foundation
|
||||||
|
Copyright (c) 2003-2004, Mark Borgerding
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
- Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
- Neither the name of the Xiph.Org Foundation nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION
|
||||||
|
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
125
third_party/rnnoise/README
vendored
Normal file
125
third_party/rnnoise/README
vendored
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
RNNoise is a noise suppression library based on a recurrent neural network.
|
||||||
|
A description of the algorithm is provided in the following paper:
|
||||||
|
|
||||||
|
J.-M. Valin, A Hybrid DSP/Deep Learning Approach to Real-Time Full-Band Speech
|
||||||
|
Enhancement, Proceedings of IEEE Multimedia Signal Processing (MMSP) Workshop,
|
||||||
|
arXiv:1709.08243, 2018.
|
||||||
|
https://arxiv.org/pdf/1709.08243.pdf
|
||||||
|
|
||||||
|
An interactive demo of version 0.1 is available at: https://jmvalin.ca/demo/rnnoise/
|
||||||
|
|
||||||
|
To compile, just type:
|
||||||
|
% ./autogen.sh
|
||||||
|
% ./configure
|
||||||
|
% make
|
||||||
|
|
||||||
|
Optionally:
|
||||||
|
% make install
|
||||||
|
|
||||||
|
It is recommended to either set -march= in the CFLAGS to an architecture
|
||||||
|
with AVX2 support or to add --enable-x86-rtcd to the configure script
|
||||||
|
so that AVX2 (or SSE4.1) can at least be used as an option.
|
||||||
|
Note that the autogen.sh script will automatically download the model files
|
||||||
|
from the Xiph.Org servers, since those are too large to put in Git.
|
||||||
|
|
||||||
|
While it is meant to be used as a library, a simple command-line tool is
|
||||||
|
provided as an example. It operates on RAW 16-bit (machine endian) mono
|
||||||
|
PCM files sampled at 48 kHz. It can be used as:
|
||||||
|
|
||||||
|
% ./examples/rnnoise_demo <noisy speech> <output denoised>
|
||||||
|
|
||||||
|
The output is also a 16-bit raw PCM file.
|
||||||
|
NOTE AGAIN, THE INPUT and OUTPUT ARE IN RAW FORMAT, NOT WAV.
|
||||||
|
|
||||||
|
The latest version of the source is available from
|
||||||
|
https://gitlab.xiph.org/xiph/rnnoise . The GitHub repository
|
||||||
|
is a convenience copy.
|
||||||
|
|
||||||
|
== Training ==
|
||||||
|
|
||||||
|
The models distributed with RNNoise are now trained using only the publicly
|
||||||
|
available datasets listed below and using the training precedure described
|
||||||
|
here. Exact results will still depend on the the exact mix of data used,
|
||||||
|
on how long the training is performed and on the various random seeds involved.
|
||||||
|
|
||||||
|
To train an RNNoise model, you need both clean speech data, and noise data.
|
||||||
|
Both need to be sampled at 48 kHz, in 16-bit PCM format (machine endian).
|
||||||
|
Clean speech data can be obtained from the datasets listed in the datasets.txt
|
||||||
|
file, or by downloaded the already-concatenation of those files in
|
||||||
|
https://media.xiph.org/rnnoise/data/tts_speech_48k.sw
|
||||||
|
For noise data, we suggest the background_noise.sw and foreground_noise.sw
|
||||||
|
(or later versions) noise files from https://media.xiph.org/rnnoise/data/
|
||||||
|
The foreground_noise.sw file contains noise signals that are meant to be added
|
||||||
|
to the background noise (e.g. keyboard sounds). Optionally, the foreground noise
|
||||||
|
file can even be denoised with a traditional denoiser (e.g. libspeexdsp) to
|
||||||
|
keep only the transient components. For background noise, the data from the
|
||||||
|
original RNNoise noise collection have now been sufficiently filtered to
|
||||||
|
provide good results -- either alone or in combination with the
|
||||||
|
background_noise.sw file. The dataset can be downloaded (updated Jan 30th 2025)
|
||||||
|
from: https://media.xiph.org/rnnoise/rnnoise_contributions.tar.gz
|
||||||
|
|
||||||
|
The first step is to take the speech and noise, and mix them in a variety of
|
||||||
|
ways to simulate real life conditions (including pauses, filtering and more).
|
||||||
|
Assuming the files are called speech.pcm and noise.pcm, start by generating
|
||||||
|
the training feature data with:
|
||||||
|
|
||||||
|
% ./dump_features speech.pcm background_noise.pcm foreground_noise.pcm features.f32 <count>
|
||||||
|
where <count> is the number of sequences to process. The number of sequences
|
||||||
|
should be at least 10000, but the more the better (200000 or more is
|
||||||
|
recommended).
|
||||||
|
|
||||||
|
Optionally, training can also simulate reverberation, in which case room impulse
|
||||||
|
responses (RIR) are also needed. Limited RIR data is available at:
|
||||||
|
https://media.xiph.org/rnnoise/data/measured_rirs-v2.tar.gz
|
||||||
|
The format for those is raw 32-bit floating-point (files are little endian).
|
||||||
|
Assuming a list of all the RIR files is contained in a rir_list.txt file,
|
||||||
|
the training feature data can be generated with:
|
||||||
|
|
||||||
|
% ./dump_features -rir_list rir_list.txt speech.pcm background_noise.pcm foreground_noise.pcm features.f32 <count>
|
||||||
|
|
||||||
|
To make the feature generation faster, you can use the script provided in
|
||||||
|
script/dump_features_parallel.sh (you will need to modify the script if you
|
||||||
|
want to add RIR augmentation).
|
||||||
|
|
||||||
|
To use it:
|
||||||
|
% script/dump_features_parallel.sh ./dump_features speech.pcm background_noise.pcm foreground_noise.pcm features.f32 <count> rir_list.txt
|
||||||
|
which will run nb_processes processes, each for count sequences, and
|
||||||
|
concatenate the output to a single file.
|
||||||
|
|
||||||
|
Once the feature file is computed, you can start the training with:
|
||||||
|
% python3 train_rnnoise.py features.f32 output_directory
|
||||||
|
|
||||||
|
Choose a number of epochs (using --epochs) that leads to about 75000 weight
|
||||||
|
updates. The training will produce .pth files, e.g. rnnoise_50.pth .
|
||||||
|
The next step is to convert the model to C files using:
|
||||||
|
|
||||||
|
% python3 dump_rnnoise_weights.py --quantize rnnoise_50.pth rnnoise_c
|
||||||
|
|
||||||
|
which will produce the rnnoise_data.c and rnnoise_data.h files in the
|
||||||
|
rnnoise_c directory.
|
||||||
|
|
||||||
|
Copy these files to src/ and then build RNNoise using the instructions above.
|
||||||
|
|
||||||
|
For slightly better results, a trained model can be used to remove any noise
|
||||||
|
from the "clean" training speech, before restaring the denoising process
|
||||||
|
again (no need to do that more than once).
|
||||||
|
|
||||||
|
== Loadable Models ==
|
||||||
|
|
||||||
|
The model format has changed since v0.1.1. Models now use a binary
|
||||||
|
"machine endian" format. To output a model in that format, build RNNoise
|
||||||
|
with that model and use the dump_weights_blob executable to output a
|
||||||
|
weights_blob.bin binary file. That file can then be used with the
|
||||||
|
rnnoise_model_from_file() API call. Note that the model object MUST NOT
|
||||||
|
be deleted while the RNNoise state is active and the file MUST NOT
|
||||||
|
be closed.
|
||||||
|
|
||||||
|
To avoid including the default model in the build (e.g. to reduce download
|
||||||
|
size) and rely only on model loading, add -DUSE_WEIGHTS_FILE to the CFLAGS.
|
||||||
|
To be able to load different models, the model size (and header file) needs
|
||||||
|
to patch the size use during build. Otherwise the model will not load
|
||||||
|
We provide a "little" model with half as an alternative. To use the smaller
|
||||||
|
model, rename rnnoise_data_little.c to rnnoise_data.c. It is possible
|
||||||
|
to build both the regular and little binary weights and load any of them
|
||||||
|
at run time since the little model has the same size as the regular one
|
||||||
|
(except for the increased sparsity).
|
||||||
131
third_party/rnnoise/include/rnnoise.h
vendored
Normal file
131
third_party/rnnoise/include/rnnoise.h
vendored
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
/* Copyright (c) 2018 Gregor Richards
|
||||||
|
* Copyright (c) 2017 Mozilla */
|
||||||
|
/*
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
- Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||||||
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RNNOISE_H
|
||||||
|
#define RNNOISE_H 1
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef RNNOISE_EXPORT
|
||||||
|
# if defined(WIN32)
|
||||||
|
# if defined(RNNOISE_BUILD) && defined(DLL_EXPORT)
|
||||||
|
# define RNNOISE_EXPORT __declspec(dllexport)
|
||||||
|
# else
|
||||||
|
# define RNNOISE_EXPORT
|
||||||
|
# endif
|
||||||
|
# elif defined(__GNUC__) && defined(RNNOISE_BUILD)
|
||||||
|
# define RNNOISE_EXPORT __attribute__ ((visibility ("default")))
|
||||||
|
# else
|
||||||
|
# define RNNOISE_EXPORT
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct DenoiseState DenoiseState;
|
||||||
|
typedef struct RNNModel RNNModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the size of DenoiseState
|
||||||
|
*/
|
||||||
|
RNNOISE_EXPORT int rnnoise_get_size(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the number of samples processed by rnnoise_process_frame at a time
|
||||||
|
*/
|
||||||
|
RNNOISE_EXPORT int rnnoise_get_frame_size(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a pre-allocated DenoiseState
|
||||||
|
*
|
||||||
|
* If model is NULL the default model is used.
|
||||||
|
*
|
||||||
|
* See: rnnoise_create() and rnnoise_model_from_file()
|
||||||
|
*/
|
||||||
|
RNNOISE_EXPORT int rnnoise_init(DenoiseState *st, RNNModel *model);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate and initialize a DenoiseState
|
||||||
|
*
|
||||||
|
* If model is NULL the default model is used.
|
||||||
|
*
|
||||||
|
* The returned pointer MUST be freed with rnnoise_destroy().
|
||||||
|
*/
|
||||||
|
RNNOISE_EXPORT DenoiseState *rnnoise_create(RNNModel *model);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free a DenoiseState produced by rnnoise_create.
|
||||||
|
*
|
||||||
|
* The optional custom model must be freed by rnnoise_model_free() after.
|
||||||
|
*/
|
||||||
|
RNNOISE_EXPORT void rnnoise_destroy(DenoiseState *st);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Denoise a frame of samples
|
||||||
|
*
|
||||||
|
* in and out must be at least rnnoise_get_frame_size() large.
|
||||||
|
*/
|
||||||
|
RNNOISE_EXPORT float rnnoise_process_frame(DenoiseState *st, float *out, const float *in);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a model from a memory buffer
|
||||||
|
*
|
||||||
|
* It must be deallocated with rnnoise_model_free() and the buffer must remain
|
||||||
|
* valid until after the returned object is destroyed.
|
||||||
|
*/
|
||||||
|
RNNOISE_EXPORT RNNModel *rnnoise_model_from_buffer(const void *ptr, int len);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a model from a file
|
||||||
|
*
|
||||||
|
* It must be deallocated with rnnoise_model_free() and the file must not be
|
||||||
|
* closed until the returned object is destroyed.
|
||||||
|
*/
|
||||||
|
RNNOISE_EXPORT RNNModel *rnnoise_model_from_file(FILE *f);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a model from a file name
|
||||||
|
*
|
||||||
|
* It must be deallocated with rnnoise_model_free()
|
||||||
|
*/
|
||||||
|
RNNOISE_EXPORT RNNModel *rnnoise_model_from_filename(const char *filename);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free a custom model
|
||||||
|
*
|
||||||
|
* It must be called after all the DenoiseStates referring to it are freed.
|
||||||
|
*/
|
||||||
|
RNNOISE_EXPORT void rnnoise_model_free(RNNModel *model);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
182
third_party/rnnoise/src/_kiss_fft_guts.h
vendored
Normal file
182
third_party/rnnoise/src/_kiss_fft_guts.h
vendored
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
/*Copyright (c) 2003-2004, Mark Borgerding
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.*/
|
||||||
|
|
||||||
|
#ifndef KISS_FFT_GUTS_H
|
||||||
|
#define KISS_FFT_GUTS_H
|
||||||
|
|
||||||
|
#define MIN(a,b) ((a)<(b) ? (a):(b))
|
||||||
|
#define MAX(a,b) ((a)>(b) ? (a):(b))
|
||||||
|
|
||||||
|
/* kiss_fft.h
|
||||||
|
defines kiss_fft_scalar as either short or a float type
|
||||||
|
and defines
|
||||||
|
typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */
|
||||||
|
#include "kiss_fft.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
Explanation of macros dealing with complex math:
|
||||||
|
|
||||||
|
C_MUL(m,a,b) : m = a*b
|
||||||
|
C_FIXDIV( c , div ) : if a fixed point impl., c /= div. noop otherwise
|
||||||
|
C_SUB( res, a,b) : res = a - b
|
||||||
|
C_SUBFROM( res , a) : res -= a
|
||||||
|
C_ADDTO( res , a) : res += a
|
||||||
|
* */
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
#include "arch.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define SAMP_MAX 2147483647
|
||||||
|
#define TWID_MAX 32767
|
||||||
|
#define TRIG_UPSCALE 1
|
||||||
|
|
||||||
|
#define SAMP_MIN -SAMP_MAX
|
||||||
|
|
||||||
|
|
||||||
|
# define S_MUL(a,b) MULT16_32_Q15(b, a)
|
||||||
|
|
||||||
|
# define C_MUL(m,a,b) \
|
||||||
|
do{ (m).r = SUB32_ovflw(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \
|
||||||
|
(m).i = ADD32_ovflw(S_MUL((a).r,(b).i) , S_MUL((a).i,(b).r)); }while(0)
|
||||||
|
|
||||||
|
# define C_MULC(m,a,b) \
|
||||||
|
do{ (m).r = ADD32_ovflw(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \
|
||||||
|
(m).i = SUB32_ovflw(S_MUL((a).i,(b).r) , S_MUL((a).r,(b).i)); }while(0)
|
||||||
|
|
||||||
|
# define C_MULBYSCALAR( c, s ) \
|
||||||
|
do{ (c).r = S_MUL( (c).r , s ) ;\
|
||||||
|
(c).i = S_MUL( (c).i , s ) ; }while(0)
|
||||||
|
|
||||||
|
# define DIVSCALAR(x,k) \
|
||||||
|
(x) = S_MUL( x, (TWID_MAX-((k)>>1))/(k)+1 )
|
||||||
|
|
||||||
|
# define C_FIXDIV(c,div) \
|
||||||
|
do { DIVSCALAR( (c).r , div); \
|
||||||
|
DIVSCALAR( (c).i , div); }while (0)
|
||||||
|
|
||||||
|
#define C_ADD( res, a,b)\
|
||||||
|
do {(res).r=ADD32_ovflw((a).r,(b).r); (res).i=ADD32_ovflw((a).i,(b).i); \
|
||||||
|
}while(0)
|
||||||
|
#define C_SUB( res, a,b)\
|
||||||
|
do {(res).r=SUB32_ovflw((a).r,(b).r); (res).i=SUB32_ovflw((a).i,(b).i); \
|
||||||
|
}while(0)
|
||||||
|
#define C_ADDTO( res , a)\
|
||||||
|
do {(res).r = ADD32_ovflw((res).r, (a).r); (res).i = ADD32_ovflw((res).i,(a).i);\
|
||||||
|
}while(0)
|
||||||
|
|
||||||
|
#define C_SUBFROM( res , a)\
|
||||||
|
do {(res).r = ADD32_ovflw((res).r,(a).r); (res).i = SUB32_ovflw((res).i,(a).i); \
|
||||||
|
}while(0)
|
||||||
|
|
||||||
|
#if defined(OPUS_ARM_INLINE_ASM)
|
||||||
|
#include "arm/kiss_fft_armv4.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(OPUS_ARM_INLINE_EDSP)
|
||||||
|
#include "arm/kiss_fft_armv5e.h"
|
||||||
|
#endif
|
||||||
|
#if defined(MIPSr1_ASM)
|
||||||
|
#include "mips/kiss_fft_mipsr1.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else /* not FIXED_POINT*/
|
||||||
|
|
||||||
|
# define S_MUL(a,b) ( (a)*(b) )
|
||||||
|
#define C_MUL(m,a,b) \
|
||||||
|
do{ (m).r = (a).r*(b).r - (a).i*(b).i;\
|
||||||
|
(m).i = (a).r*(b).i + (a).i*(b).r; }while(0)
|
||||||
|
#define C_MULC(m,a,b) \
|
||||||
|
do{ (m).r = (a).r*(b).r + (a).i*(b).i;\
|
||||||
|
(m).i = (a).i*(b).r - (a).r*(b).i; }while(0)
|
||||||
|
|
||||||
|
#define C_MUL4(m,a,b) C_MUL(m,a,b)
|
||||||
|
|
||||||
|
# define C_FIXDIV(c,div) /* NOOP */
|
||||||
|
# define C_MULBYSCALAR( c, s ) \
|
||||||
|
do{ (c).r *= (s);\
|
||||||
|
(c).i *= (s); }while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CHECK_OVERFLOW_OP
|
||||||
|
# define CHECK_OVERFLOW_OP(a,op,b) /* noop */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef C_ADD
|
||||||
|
#define C_ADD( res, a,b)\
|
||||||
|
do { \
|
||||||
|
CHECK_OVERFLOW_OP((a).r,+,(b).r)\
|
||||||
|
CHECK_OVERFLOW_OP((a).i,+,(b).i)\
|
||||||
|
(res).r=(a).r+(b).r; (res).i=(a).i+(b).i; \
|
||||||
|
}while(0)
|
||||||
|
#define C_SUB( res, a,b)\
|
||||||
|
do { \
|
||||||
|
CHECK_OVERFLOW_OP((a).r,-,(b).r)\
|
||||||
|
CHECK_OVERFLOW_OP((a).i,-,(b).i)\
|
||||||
|
(res).r=(a).r-(b).r; (res).i=(a).i-(b).i; \
|
||||||
|
}while(0)
|
||||||
|
#define C_ADDTO( res , a)\
|
||||||
|
do { \
|
||||||
|
CHECK_OVERFLOW_OP((res).r,+,(a).r)\
|
||||||
|
CHECK_OVERFLOW_OP((res).i,+,(a).i)\
|
||||||
|
(res).r += (a).r; (res).i += (a).i;\
|
||||||
|
}while(0)
|
||||||
|
|
||||||
|
#define C_SUBFROM( res , a)\
|
||||||
|
do {\
|
||||||
|
CHECK_OVERFLOW_OP((res).r,-,(a).r)\
|
||||||
|
CHECK_OVERFLOW_OP((res).i,-,(a).i)\
|
||||||
|
(res).r -= (a).r; (res).i -= (a).i; \
|
||||||
|
}while(0)
|
||||||
|
#endif /* C_ADD defined */
|
||||||
|
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
/*# define KISS_FFT_COS(phase) TRIG_UPSCALE*floor(MIN(32767,MAX(-32767,.5+32768 * cos (phase))))
|
||||||
|
# define KISS_FFT_SIN(phase) TRIG_UPSCALE*floor(MIN(32767,MAX(-32767,.5+32768 * sin (phase))))*/
|
||||||
|
# define KISS_FFT_COS(phase) floor(.5+TWID_MAX*cos (phase))
|
||||||
|
# define KISS_FFT_SIN(phase) floor(.5+TWID_MAX*sin (phase))
|
||||||
|
# define HALF_OF(x) ((x)>>1)
|
||||||
|
#elif defined(USE_SIMD)
|
||||||
|
# define KISS_FFT_COS(phase) _mm_set1_ps( cos(phase) )
|
||||||
|
# define KISS_FFT_SIN(phase) _mm_set1_ps( sin(phase) )
|
||||||
|
# define HALF_OF(x) ((x)*_mm_set1_ps(.5f))
|
||||||
|
#else
|
||||||
|
# define KISS_FFT_COS(phase) (kiss_fft_scalar) cos(phase)
|
||||||
|
# define KISS_FFT_SIN(phase) (kiss_fft_scalar) sin(phase)
|
||||||
|
# define HALF_OF(x) ((x)*.5f)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define kf_cexp(x,phase) \
|
||||||
|
do{ \
|
||||||
|
(x)->r = KISS_FFT_COS(phase);\
|
||||||
|
(x)->i = KISS_FFT_SIN(phase);\
|
||||||
|
}while(0)
|
||||||
|
|
||||||
|
#define kf_cexp2(x,phase) \
|
||||||
|
do{ \
|
||||||
|
(x)->r = TRIG_UPSCALE*celt_cos_norm((phase));\
|
||||||
|
(x)->i = TRIG_UPSCALE*celt_cos_norm((phase)-32768);\
|
||||||
|
}while(0)
|
||||||
|
|
||||||
|
#endif /* KISS_FFT_GUTS_H */
|
||||||
261
third_party/rnnoise/src/arch.h
vendored
Normal file
261
third_party/rnnoise/src/arch.h
vendored
Normal file
@@ -0,0 +1,261 @@
|
|||||||
|
/* Copyright (c) 2003-2008 Jean-Marc Valin
|
||||||
|
Copyright (c) 2007-2008 CSIRO
|
||||||
|
Copyright (c) 2007-2009 Xiph.Org Foundation
|
||||||
|
Written by Jean-Marc Valin */
|
||||||
|
/**
|
||||||
|
@file arch.h
|
||||||
|
@brief Various architecture definitions for CELT
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
- Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||||
|
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ARCH_H
|
||||||
|
#define ARCH_H
|
||||||
|
|
||||||
|
#include "opus_types.h"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
# if !defined(__GNUC_PREREQ)
|
||||||
|
# if defined(__GNUC__)&&defined(__GNUC_MINOR__)
|
||||||
|
# define __GNUC_PREREQ(_maj,_min) \
|
||||||
|
((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min))
|
||||||
|
# else
|
||||||
|
# define __GNUC_PREREQ(_maj,_min) 0
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#define CELT_SIG_SCALE 32768.f
|
||||||
|
|
||||||
|
#define celt_fatal(str) _celt_fatal(str, __FILE__, __LINE__);
|
||||||
|
#ifdef ENABLE_ASSERTIONS
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#ifdef __GNUC__
|
||||||
|
__attribute__((noreturn))
|
||||||
|
#endif
|
||||||
|
static OPUS_INLINE void _celt_fatal(const char *str, const char *file, int line)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
#define celt_assert(cond) {if (!(cond)) {celt_fatal("assertion failed: " #cond);}}
|
||||||
|
#define celt_assert2(cond, message) {if (!(cond)) {celt_fatal("assertion failed: " #cond "\n" message);}}
|
||||||
|
#else
|
||||||
|
#define celt_assert(cond)
|
||||||
|
#define celt_assert2(cond, message)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define IMUL32(a,b) ((a)*(b))
|
||||||
|
|
||||||
|
#define MIN16(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum 16-bit value. */
|
||||||
|
#define MAX16(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 16-bit value. */
|
||||||
|
#define MIN32(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum 32-bit value. */
|
||||||
|
#define MAX32(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 32-bit value. */
|
||||||
|
#define IMIN(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum int value. */
|
||||||
|
#define IMAX(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum int value. */
|
||||||
|
#define UADD32(a,b) ((a)+(b))
|
||||||
|
#define USUB32(a,b) ((a)-(b))
|
||||||
|
|
||||||
|
/* Set this if opus_int64 is a native type of the CPU. */
|
||||||
|
/* Assume that all LP64 architectures have fast 64-bit types; also x86_64
|
||||||
|
(which can be ILP32 for x32) and Win64 (which is LLP64). */
|
||||||
|
#if defined(__x86_64__) || defined(__LP64__) || defined(_WIN64)
|
||||||
|
#define OPUS_FAST_INT64 1
|
||||||
|
#else
|
||||||
|
#define OPUS_FAST_INT64 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PRINT_MIPS(file)
|
||||||
|
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
|
||||||
|
typedef opus_int16 opus_val16;
|
||||||
|
typedef opus_int32 opus_val32;
|
||||||
|
typedef opus_int64 opus_val64;
|
||||||
|
|
||||||
|
typedef opus_val32 celt_sig;
|
||||||
|
typedef opus_val16 celt_norm;
|
||||||
|
typedef opus_val32 celt_ener;
|
||||||
|
|
||||||
|
#define Q15ONE 32767
|
||||||
|
|
||||||
|
#define SIG_SHIFT 12
|
||||||
|
/* Safe saturation value for 32-bit signals. Should be less than
|
||||||
|
2^31*(1-0.85) to avoid blowing up on DC at deemphasis.*/
|
||||||
|
#define SIG_SAT (300000000)
|
||||||
|
|
||||||
|
#define NORM_SCALING 16384
|
||||||
|
|
||||||
|
#define DB_SHIFT 10
|
||||||
|
|
||||||
|
#define EPSILON 1
|
||||||
|
#define VERY_SMALL 0
|
||||||
|
#define VERY_LARGE16 ((opus_val16)32767)
|
||||||
|
#define Q15_ONE ((opus_val16)32767)
|
||||||
|
|
||||||
|
#define SCALEIN(a) (a)
|
||||||
|
#define SCALEOUT(a) (a)
|
||||||
|
|
||||||
|
#define ABS16(x) ((x) < 0 ? (-(x)) : (x))
|
||||||
|
#define ABS32(x) ((x) < 0 ? (-(x)) : (x))
|
||||||
|
|
||||||
|
static OPUS_INLINE opus_int16 SAT16(opus_int32 x) {
|
||||||
|
return x > 32767 ? 32767 : x < -32768 ? -32768 : (opus_int16)x;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef FIXED_DEBUG
|
||||||
|
#include "fixed_debug.h"
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include "fixed_generic.h"
|
||||||
|
|
||||||
|
#ifdef OPUS_ARM_PRESUME_AARCH64_NEON_INTR
|
||||||
|
#include "arm/fixed_arm64.h"
|
||||||
|
#elif OPUS_ARM_INLINE_EDSP
|
||||||
|
#include "arm/fixed_armv5e.h"
|
||||||
|
#elif defined (OPUS_ARM_INLINE_ASM)
|
||||||
|
#include "arm/fixed_armv4.h"
|
||||||
|
#elif defined (BFIN_ASM)
|
||||||
|
#include "fixed_bfin.h"
|
||||||
|
#elif defined (TI_C5X_ASM)
|
||||||
|
#include "fixed_c5x.h"
|
||||||
|
#elif defined (TI_C6X_ASM)
|
||||||
|
#include "fixed_c6x.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else /* FIXED_POINT */
|
||||||
|
|
||||||
|
typedef float opus_val16;
|
||||||
|
typedef float opus_val32;
|
||||||
|
typedef float opus_val64;
|
||||||
|
|
||||||
|
typedef float celt_sig;
|
||||||
|
typedef float celt_norm;
|
||||||
|
typedef float celt_ener;
|
||||||
|
|
||||||
|
#ifdef FLOAT_APPROX
|
||||||
|
/* This code should reliably detect NaN/inf even when -ffast-math is used.
|
||||||
|
Assumes IEEE 754 format. */
|
||||||
|
static OPUS_INLINE int celt_isnan(float x)
|
||||||
|
{
|
||||||
|
union {float f; opus_uint32 i;} in;
|
||||||
|
in.f = x;
|
||||||
|
return ((in.i>>23)&0xFF)==0xFF && (in.i&0x007FFFFF)!=0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#ifdef __FAST_MATH__
|
||||||
|
#error Cannot build libopus with -ffast-math unless FLOAT_APPROX is defined. This could result in crashes on extreme (e.g. NaN) input
|
||||||
|
#endif
|
||||||
|
#define celt_isnan(x) ((x)!=(x))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define Q15ONE 1.0f
|
||||||
|
|
||||||
|
#define NORM_SCALING 1.f
|
||||||
|
|
||||||
|
#define EPSILON 1e-15f
|
||||||
|
#define VERY_SMALL 1e-30f
|
||||||
|
#define VERY_LARGE16 1e15f
|
||||||
|
#define Q15_ONE ((opus_val16)1.f)
|
||||||
|
|
||||||
|
/* This appears to be the same speed as C99's fabsf() but it's more portable. */
|
||||||
|
#define ABS16(x) ((float)fabs(x))
|
||||||
|
#define ABS32(x) ((float)fabs(x))
|
||||||
|
|
||||||
|
#define QCONST16(x,bits) (x)
|
||||||
|
#define QCONST32(x,bits) (x)
|
||||||
|
|
||||||
|
#define NEG16(x) (-(x))
|
||||||
|
#define NEG32(x) (-(x))
|
||||||
|
#define NEG32_ovflw(x) (-(x))
|
||||||
|
#define EXTRACT16(x) (x)
|
||||||
|
#define EXTEND32(x) (x)
|
||||||
|
#define SHR16(a,shift) (a)
|
||||||
|
#define SHL16(a,shift) (a)
|
||||||
|
#define SHR32(a,shift) (a)
|
||||||
|
#define SHL32(a,shift) (a)
|
||||||
|
#define PSHR32(a,shift) (a)
|
||||||
|
#define VSHR32(a,shift) (a)
|
||||||
|
|
||||||
|
#define PSHR(a,shift) (a)
|
||||||
|
#define SHR(a,shift) (a)
|
||||||
|
#define SHL(a,shift) (a)
|
||||||
|
#define SATURATE(x,a) (x)
|
||||||
|
#define SATURATE16(x) (x)
|
||||||
|
|
||||||
|
#define ROUND16(a,shift) (a)
|
||||||
|
#define SROUND16(a,shift) (a)
|
||||||
|
#define HALF16(x) (.5f*(x))
|
||||||
|
#define HALF32(x) (.5f*(x))
|
||||||
|
|
||||||
|
#define ADD16(a,b) ((a)+(b))
|
||||||
|
#define SUB16(a,b) ((a)-(b))
|
||||||
|
#define ADD32(a,b) ((a)+(b))
|
||||||
|
#define SUB32(a,b) ((a)-(b))
|
||||||
|
#define ADD32_ovflw(a,b) ((a)+(b))
|
||||||
|
#define SUB32_ovflw(a,b) ((a)-(b))
|
||||||
|
#define MULT16_16_16(a,b) ((a)*(b))
|
||||||
|
#define MULT16_16(a,b) ((opus_val32)(a)*(opus_val32)(b))
|
||||||
|
#define MAC16_16(c,a,b) ((c)+(opus_val32)(a)*(opus_val32)(b))
|
||||||
|
|
||||||
|
#define MULT16_32_Q15(a,b) ((a)*(b))
|
||||||
|
#define MULT16_32_Q16(a,b) ((a)*(b))
|
||||||
|
|
||||||
|
#define MULT32_32_Q31(a,b) ((a)*(b))
|
||||||
|
|
||||||
|
#define MAC16_32_Q15(c,a,b) ((c)+(a)*(b))
|
||||||
|
#define MAC16_32_Q16(c,a,b) ((c)+(a)*(b))
|
||||||
|
|
||||||
|
#define MULT16_16_Q11_32(a,b) ((a)*(b))
|
||||||
|
#define MULT16_16_Q11(a,b) ((a)*(b))
|
||||||
|
#define MULT16_16_Q13(a,b) ((a)*(b))
|
||||||
|
#define MULT16_16_Q14(a,b) ((a)*(b))
|
||||||
|
#define MULT16_16_Q15(a,b) ((a)*(b))
|
||||||
|
#define MULT16_16_P15(a,b) ((a)*(b))
|
||||||
|
#define MULT16_16_P13(a,b) ((a)*(b))
|
||||||
|
#define MULT16_16_P14(a,b) ((a)*(b))
|
||||||
|
#define MULT16_32_P16(a,b) ((a)*(b))
|
||||||
|
|
||||||
|
#define DIV32_16(a,b) (((opus_val32)(a))/(opus_val16)(b))
|
||||||
|
#define DIV32(a,b) (((opus_val32)(a))/(opus_val32)(b))
|
||||||
|
|
||||||
|
#define SCALEIN(a) ((a)*CELT_SIG_SCALE)
|
||||||
|
#define SCALEOUT(a) ((a)*(1/CELT_SIG_SCALE))
|
||||||
|
|
||||||
|
#define SIG2WORD16(x) (x)
|
||||||
|
|
||||||
|
#endif /* !FIXED_POINT */
|
||||||
|
|
||||||
|
#ifndef GLOBAL_STACK_SIZE
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
#define GLOBAL_STACK_SIZE 120000
|
||||||
|
#else
|
||||||
|
#define GLOBAL_STACK_SIZE 120000
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* ARCH_H */
|
||||||
174
third_party/rnnoise/src/celt_lpc.c
vendored
Normal file
174
third_party/rnnoise/src/celt_lpc.c
vendored
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
/* Copyright (c) 2009-2010 Xiph.Org Foundation
|
||||||
|
Written by Jean-Marc Valin */
|
||||||
|
/*
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
- Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||||
|
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "celt_lpc.h"
|
||||||
|
#include "arch.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "pitch.h"
|
||||||
|
#include "denoise.h"
|
||||||
|
|
||||||
|
void rnn_lpc(
|
||||||
|
opus_val16 *_lpc, /* out: [0...p-1] LPC coefficients */
|
||||||
|
const opus_val32 *ac, /* in: [0...p] autocorrelation values */
|
||||||
|
int p
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
opus_val32 r;
|
||||||
|
opus_val32 error = ac[0];
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
opus_val32 lpc[LPC_ORDER];
|
||||||
|
#else
|
||||||
|
float *lpc = _lpc;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RNN_CLEAR(lpc, p);
|
||||||
|
if (ac[0] != 0)
|
||||||
|
{
|
||||||
|
for (i = 0; i < p; i++) {
|
||||||
|
/* Sum up this iteration's reflection coefficient */
|
||||||
|
opus_val32 rr = 0;
|
||||||
|
for (j = 0; j < i; j++)
|
||||||
|
rr += MULT32_32_Q31(lpc[j],ac[i - j]);
|
||||||
|
rr += SHR32(ac[i + 1],3);
|
||||||
|
r = -SHL32(rr,3)/error;
|
||||||
|
/* Update LPC coefficients and total error */
|
||||||
|
lpc[i] = SHR32(r,3);
|
||||||
|
for (j = 0; j < (i+1)>>1; j++)
|
||||||
|
{
|
||||||
|
opus_val32 tmp1, tmp2;
|
||||||
|
tmp1 = lpc[j];
|
||||||
|
tmp2 = lpc[i-1-j];
|
||||||
|
lpc[j] = tmp1 + MULT32_32_Q31(r,tmp2);
|
||||||
|
lpc[i-1-j] = tmp2 + MULT32_32_Q31(r,tmp1);
|
||||||
|
}
|
||||||
|
|
||||||
|
error = error - MULT32_32_Q31(MULT32_32_Q31(r,r),error);
|
||||||
|
/* Bail out once we get 30 dB gain */
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
if (error<SHR32(ac[0],10))
|
||||||
|
break;
|
||||||
|
#else
|
||||||
|
if (error<.001f*ac[0])
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
for (i=0;i<p;i++)
|
||||||
|
_lpc[i] = ROUND16(lpc[i],16);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int rnn_autocorr(
|
||||||
|
const opus_val16 *x, /* in: [0...n-1] samples x */
|
||||||
|
opus_val32 *ac, /* out: [0...lag-1] ac values */
|
||||||
|
const opus_val16 *window,
|
||||||
|
int overlap,
|
||||||
|
int lag,
|
||||||
|
int n)
|
||||||
|
{
|
||||||
|
opus_val32 d;
|
||||||
|
int i, k;
|
||||||
|
int fastN=n-lag;
|
||||||
|
int shift;
|
||||||
|
const opus_val16 *xptr;
|
||||||
|
opus_val16 xx[PITCH_BUF_SIZE/2];
|
||||||
|
celt_assert(n>0);
|
||||||
|
celt_assert(n<=PITCH_BUF_SIZE/2)
|
||||||
|
celt_assert(overlap>=0);
|
||||||
|
if (overlap == 0)
|
||||||
|
{
|
||||||
|
xptr = x;
|
||||||
|
} else {
|
||||||
|
for (i=0;i<n;i++)
|
||||||
|
xx[i] = x[i];
|
||||||
|
for (i=0;i<overlap;i++)
|
||||||
|
{
|
||||||
|
xx[i] = MULT16_16_Q15(x[i],window[i]);
|
||||||
|
xx[n-i-1] = MULT16_16_Q15(x[n-i-1],window[i]);
|
||||||
|
}
|
||||||
|
xptr = xx;
|
||||||
|
}
|
||||||
|
shift=0;
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
{
|
||||||
|
opus_val32 ac0;
|
||||||
|
ac0 = 1+(n<<7);
|
||||||
|
if (n&1) ac0 += SHR32(MULT16_16(xptr[0],xptr[0]),9);
|
||||||
|
for(i=(n&1);i<n;i+=2)
|
||||||
|
{
|
||||||
|
ac0 += SHR32(MULT16_16(xptr[i],xptr[i]),9);
|
||||||
|
ac0 += SHR32(MULT16_16(xptr[i+1],xptr[i+1]),9);
|
||||||
|
}
|
||||||
|
|
||||||
|
shift = celt_ilog2(ac0)-30+10;
|
||||||
|
shift = (shift)/2;
|
||||||
|
if (shift>0)
|
||||||
|
{
|
||||||
|
for(i=0;i<n;i++)
|
||||||
|
xx[i] = PSHR32(xptr[i], shift);
|
||||||
|
xptr = xx;
|
||||||
|
} else
|
||||||
|
shift = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
rnn_pitch_xcorr(xptr, xptr, ac, fastN, lag+1);
|
||||||
|
for (k=0;k<=lag;k++)
|
||||||
|
{
|
||||||
|
for (i = k+fastN, d = 0; i < n; i++)
|
||||||
|
d = MAC16_16(d, xptr[i], xptr[i-k]);
|
||||||
|
ac[k] += d;
|
||||||
|
}
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
shift = 2*shift;
|
||||||
|
if (shift<=0)
|
||||||
|
ac[0] += SHL32((opus_int32)1, -shift);
|
||||||
|
if (ac[0] < 268435456)
|
||||||
|
{
|
||||||
|
int shift2 = 29 - EC_ILOG(ac[0]);
|
||||||
|
for (i=0;i<=lag;i++)
|
||||||
|
ac[i] = SHL32(ac[i], shift2);
|
||||||
|
shift -= shift2;
|
||||||
|
} else if (ac[0] >= 536870912)
|
||||||
|
{
|
||||||
|
int shift2=1;
|
||||||
|
if (ac[0] >= 1073741824)
|
||||||
|
shift2++;
|
||||||
|
for (i=0;i<=lag;i++)
|
||||||
|
ac[i] = SHR32(ac[i], shift2);
|
||||||
|
shift += shift2;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return shift;
|
||||||
|
}
|
||||||
45
third_party/rnnoise/src/celt_lpc.h
vendored
Normal file
45
third_party/rnnoise/src/celt_lpc.h
vendored
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/* Copyright (c) 2009-2010 Xiph.Org Foundation
|
||||||
|
Written by Jean-Marc Valin */
|
||||||
|
/*
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
- Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||||
|
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PLC_H
|
||||||
|
#define PLC_H
|
||||||
|
|
||||||
|
#include "arch.h"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#if defined(OPUS_X86_MAY_HAVE_SSE4_1)
|
||||||
|
#include "x86/celt_lpc_sse.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define LPC_ORDER 24
|
||||||
|
|
||||||
|
void rnn_lpc(opus_val16 *_lpc, const opus_val32 *ac, int p);
|
||||||
|
|
||||||
|
int rnn_autocorr(const opus_val16 *x, opus_val32 *ac,
|
||||||
|
const opus_val16 *window, int overlap, int lag, int n);
|
||||||
|
|
||||||
|
#endif /* PLC_H */
|
||||||
56
third_party/rnnoise/src/common.h
vendored
Normal file
56
third_party/rnnoise/src/common.h
vendored
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#ifndef COMMON_H
|
||||||
|
#define COMMON_H
|
||||||
|
|
||||||
|
#include "stdlib.h"
|
||||||
|
#include "string.h"
|
||||||
|
|
||||||
|
#define RNN_INLINE inline
|
||||||
|
#define OPUS_INLINE inline
|
||||||
|
|
||||||
|
|
||||||
|
/** RNNoise wrapper for malloc(). To do your own dynamic allocation, all you need t
|
||||||
|
o do is replace this function and rnnoise_free */
|
||||||
|
#ifndef OVERRIDE_RNNOISE_ALLOC
|
||||||
|
static RNN_INLINE void *rnnoise_alloc (size_t size)
|
||||||
|
{
|
||||||
|
return malloc(size);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** RNNoise wrapper for free(). To do your own dynamic allocation, all you need to do is replace this function and rnnoise_alloc */
|
||||||
|
#ifndef OVERRIDE_RNNOISE_FREE
|
||||||
|
static RNN_INLINE void rnnoise_free (void *ptr)
|
||||||
|
{
|
||||||
|
free(ptr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Copy n elements from src to dst. The 0* term provides compile-time type checking */
|
||||||
|
#ifndef OVERRIDE_RNN_COPY
|
||||||
|
#define RNN_COPY(dst, src, n) (memcpy((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) ))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Copy n elements from src to dst, allowing overlapping regions. The 0* term
|
||||||
|
provides compile-time type checking */
|
||||||
|
#ifndef OVERRIDE_RNN_MOVE
|
||||||
|
#define RNN_MOVE(dst, src, n) (memmove((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) ))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Set n elements of dst to zero */
|
||||||
|
#ifndef OVERRIDE_RNN_CLEAR
|
||||||
|
#define RNN_CLEAR(dst, n) (memset((dst), 0, (n)*sizeof(*(dst))))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
# if !defined(OPUS_GNUC_PREREQ)
|
||||||
|
# if defined(__GNUC__)&&defined(__GNUC_MINOR__)
|
||||||
|
# define OPUS_GNUC_PREREQ(_maj,_min) \
|
||||||
|
((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min))
|
||||||
|
# else
|
||||||
|
# define OPUS_GNUC_PREREQ(_maj,_min) 0
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
53
third_party/rnnoise/src/cpu_support.h
vendored
Normal file
53
third_party/rnnoise/src/cpu_support.h
vendored
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/* Copyright (c) 2010 Xiph.Org Foundation
|
||||||
|
* Copyright (c) 2013 Parrot */
|
||||||
|
/*
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
- Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||||
|
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CPU_SUPPORT_H
|
||||||
|
#define CPU_SUPPORT_H
|
||||||
|
|
||||||
|
#include "opus_types.h"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#ifdef RNN_ENABLE_X86_RTCD
|
||||||
|
|
||||||
|
#include "x86/x86cpu.h"
|
||||||
|
/* We currently support 5 x86 variants:
|
||||||
|
* arch[0] -> sse2
|
||||||
|
* arch[1] -> sse4.1
|
||||||
|
* arch[2] -> avx2
|
||||||
|
*/
|
||||||
|
#define OPUS_ARCHMASK 3
|
||||||
|
int rnn_select_arch(void);
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define OPUS_ARCHMASK 0
|
||||||
|
|
||||||
|
static OPUS_INLINE int rnn_select_arch(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
505
third_party/rnnoise/src/denoise.c
vendored
Normal file
505
third_party/rnnoise/src/denoise.c
vendored
Normal file
@@ -0,0 +1,505 @@
|
|||||||
|
/* Copyright (c) 2024 Jean-Marc Valin
|
||||||
|
* Copyright (c) 2018 Gregor Richards
|
||||||
|
* Copyright (c) 2017 Mozilla */
|
||||||
|
/*
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
- Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||||||
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "kiss_fft.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "denoise.h"
|
||||||
|
#include <math.h>
|
||||||
|
#include "rnnoise.h"
|
||||||
|
#include "pitch.h"
|
||||||
|
#include "arch.h"
|
||||||
|
#include "rnn.h"
|
||||||
|
#include "cpu_support.h"
|
||||||
|
|
||||||
|
#define SQUARE(x) ((x)*(x))
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef TRAINING
|
||||||
|
#define TRAINING 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* ERB bandwidths going in reverse from 20 kHz and then replacing the 700 and 800
|
||||||
|
with just 750 because having 32 bands is convenient for the DNN.
|
||||||
|
B(1)=400;
|
||||||
|
for k=2:35
|
||||||
|
B(k) = B(k-1) - max(2, round(24.7*(4.37*B(k-1)/20+1)/50));
|
||||||
|
end
|
||||||
|
printf("%d, ", B(end:-1:1));
|
||||||
|
printf("\n")
|
||||||
|
*/
|
||||||
|
const int eband20ms[NB_BANDS+2] = {
|
||||||
|
/*0 100 200 300 400 500 600 750 900 1.1 1.2 1.4 1.6 1.8 2.1 2.4 2.7 3.0 3.4 3.9 4.4 4.9 5.5 6.2 7.0 7.9 8.8 9.9 11.2 12.6 14.1 15.9 17.8 20.0*/
|
||||||
|
0, 2, 4, 6, 8, 10, 12, 15, 18, 21, 24, 28, 32, 36, 41, 47, 53, 60, 68, 77, 87, 98, 110, 124, 140, 157, 176, 198, 223, 251, 282, 317, 356, 400};
|
||||||
|
|
||||||
|
|
||||||
|
struct DenoiseState {
|
||||||
|
RNNoise model;
|
||||||
|
#if !TRAINING
|
||||||
|
int arch;
|
||||||
|
#endif
|
||||||
|
float analysis_mem[FRAME_SIZE];
|
||||||
|
int memid;
|
||||||
|
float synthesis_mem[FRAME_SIZE];
|
||||||
|
float pitch_buf[PITCH_BUF_SIZE];
|
||||||
|
float pitch_enh_buf[PITCH_BUF_SIZE];
|
||||||
|
float last_gain;
|
||||||
|
int last_period;
|
||||||
|
float mem_hp_x[2];
|
||||||
|
float lastg[NB_BANDS];
|
||||||
|
RNNState rnn;
|
||||||
|
kiss_fft_cpx delayed_X[FREQ_SIZE];
|
||||||
|
kiss_fft_cpx delayed_P[FREQ_SIZE];
|
||||||
|
float delayed_Ex[NB_BANDS], delayed_Ep[NB_BANDS];
|
||||||
|
float delayed_Exp[NB_BANDS];
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
static void compute_band_energy(float *bandE, const kiss_fft_cpx *X) {
|
||||||
|
int i;
|
||||||
|
float sum[NB_BANDS+2] = {0};
|
||||||
|
for (i=0;i<NB_BANDS+1;i++)
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
int band_size;
|
||||||
|
band_size = eband20ms[i+1]-eband20ms[i];
|
||||||
|
for (j=0;j<band_size;j++) {
|
||||||
|
float tmp;
|
||||||
|
float frac = (float)j/band_size;
|
||||||
|
tmp = SQUARE(X[eband20ms[i] + j].r);
|
||||||
|
tmp += SQUARE(X[eband20ms[i] + j].i);
|
||||||
|
sum[i] += (1-frac)*tmp;
|
||||||
|
sum[i+1] += frac*tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sum[1] = (sum[0]+sum[1])*2/3;
|
||||||
|
sum[NB_BANDS] = (sum[NB_BANDS]+sum[NB_BANDS+1])*2/3;
|
||||||
|
for (i=0;i<NB_BANDS;i++)
|
||||||
|
{
|
||||||
|
bandE[i] = sum[i+1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void compute_band_corr(float *bandE, const kiss_fft_cpx *X, const kiss_fft_cpx *P) {
|
||||||
|
int i;
|
||||||
|
float sum[NB_BANDS+2] = {0};
|
||||||
|
for (i=0;i<NB_BANDS+1;i++)
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
int band_size;
|
||||||
|
band_size = eband20ms[i+1]-eband20ms[i];
|
||||||
|
for (j=0;j<band_size;j++) {
|
||||||
|
float tmp;
|
||||||
|
float frac = (float)j/band_size;
|
||||||
|
tmp = X[eband20ms[i] + j].r * P[eband20ms[i] + j].r;
|
||||||
|
tmp += X[eband20ms[i] + j].i * P[eband20ms[i] + j].i;
|
||||||
|
sum[i] += (1-frac)*tmp;
|
||||||
|
sum[i+1] += frac*tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sum[1] = (sum[0]+sum[1])*2/3;
|
||||||
|
sum[NB_BANDS] = (sum[NB_BANDS]+sum[NB_BANDS+1])*2/3;
|
||||||
|
for (i=0;i<NB_BANDS;i++)
|
||||||
|
{
|
||||||
|
bandE[i] = sum[i+1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void interp_band_gain(float *g, const float *bandE) {
|
||||||
|
int i,j;
|
||||||
|
memset(g, 0, FREQ_SIZE);
|
||||||
|
for (i=1;i<NB_BANDS;i++)
|
||||||
|
{
|
||||||
|
int band_size;
|
||||||
|
band_size = eband20ms[i+1]-eband20ms[i];
|
||||||
|
for (j=0;j<band_size;j++) {
|
||||||
|
float frac = (float)j/band_size;
|
||||||
|
g[eband20ms[i] + j] = (1-frac)*bandE[i-1] + frac*bandE[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (j=0;j<eband20ms[1];j++) g[j] = bandE[0];
|
||||||
|
for (j=eband20ms[NB_BANDS];j<eband20ms[NB_BANDS+1];j++) g[j] = bandE[NB_BANDS-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
extern const float rnn_dct_table[];
|
||||||
|
extern const kiss_fft_state rnn_kfft;
|
||||||
|
extern const float rnn_half_window[];
|
||||||
|
|
||||||
|
static void dct(float *out, const float *in) {
|
||||||
|
int i;
|
||||||
|
for (i=0;i<NB_BANDS;i++) {
|
||||||
|
int j;
|
||||||
|
float sum = 0;
|
||||||
|
for (j=0;j<NB_BANDS;j++) {
|
||||||
|
sum += in[j] * rnn_dct_table[j*NB_BANDS + i];
|
||||||
|
}
|
||||||
|
out[i] = sum*sqrt(2./22);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static void idct(float *out, const float *in) {
|
||||||
|
int i;
|
||||||
|
for (i=0;i<NB_BANDS;i++) {
|
||||||
|
int j;
|
||||||
|
float sum = 0;
|
||||||
|
for (j=0;j<NB_BANDS;j++) {
|
||||||
|
sum += in[j] * rnn_dct_table[i*NB_BANDS + j];
|
||||||
|
}
|
||||||
|
out[i] = sum*sqrt(2./22);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void forward_transform(kiss_fft_cpx *out, const float *in) {
|
||||||
|
int i;
|
||||||
|
kiss_fft_cpx x[WINDOW_SIZE];
|
||||||
|
kiss_fft_cpx y[WINDOW_SIZE];
|
||||||
|
for (i=0;i<WINDOW_SIZE;i++) {
|
||||||
|
x[i].r = in[i];
|
||||||
|
x[i].i = 0;
|
||||||
|
}
|
||||||
|
rnn_fft(&rnn_kfft, x, y, 0);
|
||||||
|
for (i=0;i<FREQ_SIZE;i++) {
|
||||||
|
out[i] = y[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void inverse_transform(float *out, const kiss_fft_cpx *in) {
|
||||||
|
int i;
|
||||||
|
kiss_fft_cpx x[WINDOW_SIZE];
|
||||||
|
kiss_fft_cpx y[WINDOW_SIZE];
|
||||||
|
for (i=0;i<FREQ_SIZE;i++) {
|
||||||
|
x[i] = in[i];
|
||||||
|
}
|
||||||
|
for (;i<WINDOW_SIZE;i++) {
|
||||||
|
x[i].r = x[WINDOW_SIZE - i].r;
|
||||||
|
x[i].i = -x[WINDOW_SIZE - i].i;
|
||||||
|
}
|
||||||
|
rnn_fft(&rnn_kfft, x, y, 0);
|
||||||
|
/* output in reverse order for IFFT. */
|
||||||
|
out[0] = WINDOW_SIZE*y[0].r;
|
||||||
|
for (i=1;i<WINDOW_SIZE;i++) {
|
||||||
|
out[i] = WINDOW_SIZE*y[WINDOW_SIZE - i].r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void apply_window(float *x) {
|
||||||
|
int i;
|
||||||
|
for (i=0;i<FRAME_SIZE;i++) {
|
||||||
|
x[i] *= rnn_half_window[i];
|
||||||
|
x[WINDOW_SIZE - 1 - i] *= rnn_half_window[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RNNModel {
|
||||||
|
/* Set either blob or const_blob. */
|
||||||
|
const void *const_blob;
|
||||||
|
void *blob;
|
||||||
|
int blob_len;
|
||||||
|
FILE *file;
|
||||||
|
};
|
||||||
|
|
||||||
|
RNNModel *rnnoise_model_from_buffer(const void *ptr, int len) {
|
||||||
|
RNNModel *model;
|
||||||
|
model = malloc(sizeof(*model));
|
||||||
|
model->blob = NULL;
|
||||||
|
model->const_blob = ptr;
|
||||||
|
model->blob_len = len;
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
RNNModel *rnnoise_model_from_filename(const char *filename) {
|
||||||
|
RNNModel *model;
|
||||||
|
FILE *f = fopen(filename, "rb");
|
||||||
|
model = rnnoise_model_from_file(f);
|
||||||
|
model->file = f;
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
RNNModel *rnnoise_model_from_file(FILE *f) {
|
||||||
|
RNNModel *model;
|
||||||
|
model = malloc(sizeof(*model));
|
||||||
|
model->file = NULL;
|
||||||
|
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
model->blob_len = ftell(f);
|
||||||
|
fseek(f, 0, SEEK_SET);
|
||||||
|
|
||||||
|
model->const_blob = NULL;
|
||||||
|
model->blob = malloc(model->blob_len);
|
||||||
|
if (fread(model->blob, model->blob_len, 1, f) != 1)
|
||||||
|
{
|
||||||
|
rnnoise_model_free(model);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rnnoise_model_free(RNNModel *model) {
|
||||||
|
if (model->file != NULL) fclose(model->file);
|
||||||
|
if (model->blob != NULL) free(model->blob);
|
||||||
|
free(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rnnoise_get_size(void) {
|
||||||
|
return sizeof(DenoiseState);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rnnoise_get_frame_size(void) {
|
||||||
|
return FRAME_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rnnoise_init(DenoiseState *st, RNNModel *model) {
|
||||||
|
memset(st, 0, sizeof(*st));
|
||||||
|
#if !TRAINING
|
||||||
|
if (model != NULL) {
|
||||||
|
WeightArray *list;
|
||||||
|
int ret = 1;
|
||||||
|
parse_weights(&list, model->blob ? model->blob : model->const_blob, model->blob_len);
|
||||||
|
if (list != NULL) {
|
||||||
|
ret = init_rnnoise(&st->model, list);
|
||||||
|
opus_free(list);
|
||||||
|
}
|
||||||
|
if (ret != 0) return -1;
|
||||||
|
}
|
||||||
|
#ifndef USE_WEIGHTS_FILE
|
||||||
|
else {
|
||||||
|
int ret = init_rnnoise(&st->model, rnnoise_arrays);
|
||||||
|
if (ret != 0) return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
st->arch = rnn_select_arch();
|
||||||
|
#else
|
||||||
|
(void)model;
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DenoiseState *rnnoise_create(RNNModel *model) {
|
||||||
|
int ret;
|
||||||
|
DenoiseState *st;
|
||||||
|
st = malloc(rnnoise_get_size());
|
||||||
|
ret = rnnoise_init(st, model);
|
||||||
|
if (ret != 0) {
|
||||||
|
free(st);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return st;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rnnoise_destroy(DenoiseState *st) {
|
||||||
|
free(st);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if TRAINING
|
||||||
|
extern int lowpass;
|
||||||
|
extern int band_lp;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void rnn_frame_analysis(DenoiseState *st, kiss_fft_cpx *X, float *Ex, const float *in) {
|
||||||
|
int i;
|
||||||
|
float x[WINDOW_SIZE];
|
||||||
|
RNN_COPY(x, st->analysis_mem, FRAME_SIZE);
|
||||||
|
for (i=0;i<FRAME_SIZE;i++) x[FRAME_SIZE + i] = in[i];
|
||||||
|
RNN_COPY(st->analysis_mem, in, FRAME_SIZE);
|
||||||
|
apply_window(x);
|
||||||
|
forward_transform(X, x);
|
||||||
|
#if TRAINING
|
||||||
|
for (i=lowpass;i<FREQ_SIZE;i++)
|
||||||
|
X[i].r = X[i].i = 0;
|
||||||
|
#endif
|
||||||
|
compute_band_energy(Ex, X);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rnn_compute_frame_features(DenoiseState *st, kiss_fft_cpx *X, kiss_fft_cpx *P,
|
||||||
|
float *Ex, float *Ep, float *Exp, float *features, const float *in) {
|
||||||
|
int i;
|
||||||
|
float E = 0;
|
||||||
|
float Ly[NB_BANDS];
|
||||||
|
float p[WINDOW_SIZE];
|
||||||
|
float pitch_buf[PITCH_BUF_SIZE>>1];
|
||||||
|
int pitch_index;
|
||||||
|
float gain;
|
||||||
|
float *(pre[1]);
|
||||||
|
float follow, logMax;
|
||||||
|
rnn_frame_analysis(st, X, Ex, in);
|
||||||
|
RNN_MOVE(st->pitch_buf, &st->pitch_buf[FRAME_SIZE], PITCH_BUF_SIZE-FRAME_SIZE);
|
||||||
|
RNN_COPY(&st->pitch_buf[PITCH_BUF_SIZE-FRAME_SIZE], in, FRAME_SIZE);
|
||||||
|
pre[0] = &st->pitch_buf[0];
|
||||||
|
rnn_pitch_downsample(pre, pitch_buf, PITCH_BUF_SIZE, 1);
|
||||||
|
rnn_pitch_search(pitch_buf+(PITCH_MAX_PERIOD>>1), pitch_buf, PITCH_FRAME_SIZE,
|
||||||
|
PITCH_MAX_PERIOD-3*PITCH_MIN_PERIOD, &pitch_index);
|
||||||
|
pitch_index = PITCH_MAX_PERIOD-pitch_index;
|
||||||
|
|
||||||
|
gain = rnn_remove_doubling(pitch_buf, PITCH_MAX_PERIOD, PITCH_MIN_PERIOD,
|
||||||
|
PITCH_FRAME_SIZE, &pitch_index, st->last_period, st->last_gain);
|
||||||
|
st->last_period = pitch_index;
|
||||||
|
st->last_gain = gain;
|
||||||
|
for (i=0;i<WINDOW_SIZE;i++)
|
||||||
|
p[i] = st->pitch_buf[PITCH_BUF_SIZE-WINDOW_SIZE-pitch_index+i];
|
||||||
|
apply_window(p);
|
||||||
|
forward_transform(P, p);
|
||||||
|
compute_band_energy(Ep, P);
|
||||||
|
compute_band_corr(Exp, X, P);
|
||||||
|
for (i=0;i<NB_BANDS;i++) Exp[i] = Exp[i]/sqrt(.001+Ex[i]*Ep[i]);
|
||||||
|
dct(&features[NB_BANDS], Exp);
|
||||||
|
features[2*NB_BANDS] = .01*(pitch_index-300);
|
||||||
|
logMax = -2;
|
||||||
|
follow = -2;
|
||||||
|
for (i=0;i<NB_BANDS;i++) {
|
||||||
|
Ly[i] = log10(1e-2+Ex[i]);
|
||||||
|
Ly[i] = MAX16(logMax-7, MAX16(follow-1.5, Ly[i]));
|
||||||
|
logMax = MAX16(logMax, Ly[i]);
|
||||||
|
follow = MAX16(follow-1.5, Ly[i]);
|
||||||
|
E += Ex[i];
|
||||||
|
}
|
||||||
|
if (!TRAINING && E < 0.04) {
|
||||||
|
/* If there's no audio, avoid messing up the state. */
|
||||||
|
RNN_CLEAR(features, NB_FEATURES);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
dct(features, Ly);
|
||||||
|
features[0] -= 12;
|
||||||
|
features[1] -= 4;
|
||||||
|
return TRAINING && E < 0.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void frame_synthesis(DenoiseState *st, float *out, const kiss_fft_cpx *y) {
|
||||||
|
float x[WINDOW_SIZE];
|
||||||
|
int i;
|
||||||
|
inverse_transform(x, y);
|
||||||
|
apply_window(x);
|
||||||
|
for (i=0;i<FRAME_SIZE;i++) out[i] = x[i] + st->synthesis_mem[i];
|
||||||
|
RNN_COPY(st->synthesis_mem, &x[FRAME_SIZE], FRAME_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rnn_biquad(float *y, float mem[2], const float *x, const float *b, const float *a, int N) {
|
||||||
|
int i;
|
||||||
|
for (i=0;i<N;i++) {
|
||||||
|
float xi, yi;
|
||||||
|
xi = x[i];
|
||||||
|
yi = x[i] + mem[0];
|
||||||
|
mem[0] = mem[1] + (b[0]*(double)xi - a[0]*(double)yi);
|
||||||
|
mem[1] = (b[1]*(double)xi - a[1]*(double)yi);
|
||||||
|
y[i] = yi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rnn_pitch_filter(kiss_fft_cpx *X, const kiss_fft_cpx *P, const float *Ex, const float *Ep,
|
||||||
|
const float *Exp, const float *g) {
|
||||||
|
int i;
|
||||||
|
float r[NB_BANDS];
|
||||||
|
float rf[FREQ_SIZE] = {0};
|
||||||
|
float newE[NB_BANDS];
|
||||||
|
float norm[NB_BANDS];
|
||||||
|
float normf[FREQ_SIZE]={0};
|
||||||
|
for (i=0;i<NB_BANDS;i++) {
|
||||||
|
#if 0
|
||||||
|
if (Exp[i]>g[i]) r[i] = 1;
|
||||||
|
else r[i] = Exp[i]*(1-g[i])/(.001 + g[i]*(1-Exp[i]));
|
||||||
|
r[i] = MIN16(1, MAX16(0, r[i]));
|
||||||
|
#else
|
||||||
|
if (Exp[i]>g[i]) r[i] = 1;
|
||||||
|
else r[i] = SQUARE(Exp[i])*(1-SQUARE(g[i]))/(.001 + SQUARE(g[i])*(1-SQUARE(Exp[i])));
|
||||||
|
r[i] = sqrt(MIN16(1, MAX16(0, r[i])));
|
||||||
|
#endif
|
||||||
|
r[i] *= sqrt(Ex[i]/(1e-8+Ep[i]));
|
||||||
|
}
|
||||||
|
interp_band_gain(rf, r);
|
||||||
|
for (i=0;i<FREQ_SIZE;i++) {
|
||||||
|
X[i].r += rf[i]*P[i].r;
|
||||||
|
X[i].i += rf[i]*P[i].i;
|
||||||
|
}
|
||||||
|
compute_band_energy(newE, X);
|
||||||
|
for (i=0;i<NB_BANDS;i++) {
|
||||||
|
norm[i] = sqrt(Ex[i]/(1e-8+newE[i]));
|
||||||
|
}
|
||||||
|
interp_band_gain(normf, norm);
|
||||||
|
for (i=0;i<FREQ_SIZE;i++) {
|
||||||
|
X[i].r *= normf[i];
|
||||||
|
X[i].i *= normf[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float rnnoise_process_frame(DenoiseState *st, float *out, const float *in) {
|
||||||
|
int i;
|
||||||
|
kiss_fft_cpx X[FREQ_SIZE];
|
||||||
|
kiss_fft_cpx P[FREQ_SIZE];
|
||||||
|
float x[FRAME_SIZE];
|
||||||
|
float Ex[NB_BANDS], Ep[NB_BANDS];
|
||||||
|
float Exp[NB_BANDS];
|
||||||
|
float features[NB_FEATURES];
|
||||||
|
float g[NB_BANDS];
|
||||||
|
float gf[FREQ_SIZE]={1};
|
||||||
|
float vad_prob = 0;
|
||||||
|
int silence;
|
||||||
|
static const float a_hp[2] = {-1.99599, 0.99600};
|
||||||
|
static const float b_hp[2] = {-2, 1};
|
||||||
|
rnn_biquad(x, st->mem_hp_x, in, b_hp, a_hp, FRAME_SIZE);
|
||||||
|
silence = rnn_compute_frame_features(st, X, P, Ex, Ep, Exp, features, x);
|
||||||
|
|
||||||
|
if (!silence) {
|
||||||
|
#if !TRAINING
|
||||||
|
compute_rnn(&st->model, &st->rnn, g, &vad_prob, features, st->arch);
|
||||||
|
#endif
|
||||||
|
rnn_pitch_filter(st->delayed_X, st->delayed_P, st->delayed_Ex, st->delayed_Ep, st->delayed_Exp, g);
|
||||||
|
for (i=0;i<NB_BANDS;i++) {
|
||||||
|
float alpha = .6f;
|
||||||
|
/* Cap the decay at 0.6 per frame, corresponding to an RT60 of 135 ms.
|
||||||
|
That avoids unnaturally quick attenuation. */
|
||||||
|
g[i] = MAX16(g[i], alpha*st->lastg[i]);
|
||||||
|
/* Compensate for energy change across frame when computing the threshold gain.
|
||||||
|
Avoids leaking noise when energy increases (e.g. transient noise). */
|
||||||
|
st->lastg[i] = MIN16(1.f, g[i]*(st->delayed_Ex[i]+1e-3)/(Ex[i]+1e-3));
|
||||||
|
}
|
||||||
|
interp_band_gain(gf, g);
|
||||||
|
#if 1
|
||||||
|
for (i=0;i<FREQ_SIZE;i++) {
|
||||||
|
st->delayed_X[i].r *= gf[i];
|
||||||
|
st->delayed_X[i].i *= gf[i];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
frame_synthesis(st, out, st->delayed_X);
|
||||||
|
|
||||||
|
RNN_COPY(st->delayed_X, X, FREQ_SIZE);
|
||||||
|
RNN_COPY(st->delayed_P, P, FREQ_SIZE);
|
||||||
|
RNN_COPY(st->delayed_Ex, Ex, NB_BANDS);
|
||||||
|
RNN_COPY(st->delayed_Ep, Ep, NB_BANDS);
|
||||||
|
RNN_COPY(st->delayed_Exp, Exp, NB_BANDS);
|
||||||
|
return vad_prob;
|
||||||
|
}
|
||||||
|
|
||||||
56
third_party/rnnoise/src/denoise.h
vendored
Normal file
56
third_party/rnnoise/src/denoise.h
vendored
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
/* Copyright (c) 2017 Mozilla */
|
||||||
|
/*
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
- Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||||||
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "rnnoise.h"
|
||||||
|
#include "kiss_fft.h"
|
||||||
|
#include "nnet.h"
|
||||||
|
|
||||||
|
#define FRAME_SIZE 480
|
||||||
|
#define WINDOW_SIZE (2*FRAME_SIZE)
|
||||||
|
#define FREQ_SIZE (FRAME_SIZE + 1)
|
||||||
|
#define NB_BANDS 32
|
||||||
|
#define NB_FEATURES (2*NB_BANDS+1)
|
||||||
|
|
||||||
|
|
||||||
|
#define PITCH_MIN_PERIOD 60
|
||||||
|
#define PITCH_MAX_PERIOD 768
|
||||||
|
#define PITCH_FRAME_SIZE 960
|
||||||
|
#define PITCH_BUF_SIZE (PITCH_MAX_PERIOD+PITCH_FRAME_SIZE)
|
||||||
|
|
||||||
|
extern const WeightArray rnnoise_arrays[];
|
||||||
|
|
||||||
|
extern const int eband20ms[];
|
||||||
|
|
||||||
|
|
||||||
|
void rnn_biquad(float *y, float mem[2], const float *x, const float *b, const float *a, int N);
|
||||||
|
|
||||||
|
void rnn_pitch_filter(kiss_fft_cpx *X, const kiss_fft_cpx *P, const float *Ex, const float *Ep,
|
||||||
|
const float *Exp, const float *g);
|
||||||
|
|
||||||
|
void rnn_frame_analysis(DenoiseState *st, kiss_fft_cpx *X, float *Ex, const float *in);
|
||||||
|
|
||||||
|
int rnn_compute_frame_features(DenoiseState *st, kiss_fft_cpx *X, kiss_fft_cpx *P,
|
||||||
|
float *Ex, float *Ep, float *Exp, float *features, const float *in);
|
||||||
601
third_party/rnnoise/src/kiss_fft.c
vendored
Normal file
601
third_party/rnnoise/src/kiss_fft.c
vendored
Normal file
@@ -0,0 +1,601 @@
|
|||||||
|
/*Copyright (c) 2003-2004, Mark Borgerding
|
||||||
|
Lots of modifications by Jean-Marc Valin
|
||||||
|
Copyright (c) 2005-2007, Xiph.Org Foundation
|
||||||
|
Copyright (c) 2008, Xiph.Org Foundation, CSIRO
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.*/
|
||||||
|
|
||||||
|
/* This code is originally from Mark Borgerding's KISS-FFT but has been
|
||||||
|
heavily modified to better suit Opus */
|
||||||
|
|
||||||
|
#ifndef SKIP_CONFIG_H
|
||||||
|
# ifdef HAVE_CONFIG_H
|
||||||
|
# include "config.h"
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "_kiss_fft_guts.h"
|
||||||
|
#define CUSTOM_MODES
|
||||||
|
|
||||||
|
/* The guts header contains all the multiplication and addition macros that are defined for
|
||||||
|
complex numbers. It also declares the kf_ internal functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void kf_bfly2(
|
||||||
|
kiss_fft_cpx * Fout,
|
||||||
|
int m,
|
||||||
|
int N
|
||||||
|
)
|
||||||
|
{
|
||||||
|
kiss_fft_cpx * Fout2;
|
||||||
|
int i;
|
||||||
|
(void)m;
|
||||||
|
#ifdef CUSTOM_MODES
|
||||||
|
if (m==1)
|
||||||
|
{
|
||||||
|
celt_assert(m==1);
|
||||||
|
for (i=0;i<N;i++)
|
||||||
|
{
|
||||||
|
kiss_fft_cpx t;
|
||||||
|
Fout2 = Fout + 1;
|
||||||
|
t = *Fout2;
|
||||||
|
C_SUB( *Fout2 , *Fout , t );
|
||||||
|
C_ADDTO( *Fout , t );
|
||||||
|
Fout += 2;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
opus_val16 tw;
|
||||||
|
tw = QCONST16(0.7071067812f, 15);
|
||||||
|
/* We know that m==4 here because the radix-2 is just after a radix-4 */
|
||||||
|
celt_assert(m==4);
|
||||||
|
for (i=0;i<N;i++)
|
||||||
|
{
|
||||||
|
kiss_fft_cpx t;
|
||||||
|
Fout2 = Fout + 4;
|
||||||
|
t = Fout2[0];
|
||||||
|
C_SUB( Fout2[0] , Fout[0] , t );
|
||||||
|
C_ADDTO( Fout[0] , t );
|
||||||
|
|
||||||
|
t.r = S_MUL(ADD32_ovflw(Fout2[1].r, Fout2[1].i), tw);
|
||||||
|
t.i = S_MUL(SUB32_ovflw(Fout2[1].i, Fout2[1].r), tw);
|
||||||
|
C_SUB( Fout2[1] , Fout[1] , t );
|
||||||
|
C_ADDTO( Fout[1] , t );
|
||||||
|
|
||||||
|
t.r = Fout2[2].i;
|
||||||
|
t.i = -Fout2[2].r;
|
||||||
|
C_SUB( Fout2[2] , Fout[2] , t );
|
||||||
|
C_ADDTO( Fout[2] , t );
|
||||||
|
|
||||||
|
t.r = S_MUL(SUB32_ovflw(Fout2[3].i, Fout2[3].r), tw);
|
||||||
|
t.i = S_MUL(NEG32_ovflw(ADD32_ovflw(Fout2[3].i, Fout2[3].r)), tw);
|
||||||
|
C_SUB( Fout2[3] , Fout[3] , t );
|
||||||
|
C_ADDTO( Fout[3] , t );
|
||||||
|
Fout += 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void kf_bfly4(
|
||||||
|
kiss_fft_cpx * Fout,
|
||||||
|
const size_t fstride,
|
||||||
|
const kiss_fft_state *st,
|
||||||
|
int m,
|
||||||
|
int N,
|
||||||
|
int mm
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (m==1)
|
||||||
|
{
|
||||||
|
/* Degenerate case where all the twiddles are 1. */
|
||||||
|
for (i=0;i<N;i++)
|
||||||
|
{
|
||||||
|
kiss_fft_cpx scratch0, scratch1;
|
||||||
|
|
||||||
|
C_SUB( scratch0 , *Fout, Fout[2] );
|
||||||
|
C_ADDTO(*Fout, Fout[2]);
|
||||||
|
C_ADD( scratch1 , Fout[1] , Fout[3] );
|
||||||
|
C_SUB( Fout[2], *Fout, scratch1 );
|
||||||
|
C_ADDTO( *Fout , scratch1 );
|
||||||
|
C_SUB( scratch1 , Fout[1] , Fout[3] );
|
||||||
|
|
||||||
|
Fout[1].r = ADD32_ovflw(scratch0.r, scratch1.i);
|
||||||
|
Fout[1].i = SUB32_ovflw(scratch0.i, scratch1.r);
|
||||||
|
Fout[3].r = SUB32_ovflw(scratch0.r, scratch1.i);
|
||||||
|
Fout[3].i = ADD32_ovflw(scratch0.i, scratch1.r);
|
||||||
|
Fout+=4;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int j;
|
||||||
|
kiss_fft_cpx scratch[6];
|
||||||
|
const kiss_twiddle_cpx *tw1,*tw2,*tw3;
|
||||||
|
const int m2=2*m;
|
||||||
|
const int m3=3*m;
|
||||||
|
kiss_fft_cpx * Fout_beg = Fout;
|
||||||
|
for (i=0;i<N;i++)
|
||||||
|
{
|
||||||
|
Fout = Fout_beg + i*mm;
|
||||||
|
tw3 = tw2 = tw1 = st->twiddles;
|
||||||
|
/* m is guaranteed to be a multiple of 4. */
|
||||||
|
for (j=0;j<m;j++)
|
||||||
|
{
|
||||||
|
C_MUL(scratch[0],Fout[m] , *tw1 );
|
||||||
|
C_MUL(scratch[1],Fout[m2] , *tw2 );
|
||||||
|
C_MUL(scratch[2],Fout[m3] , *tw3 );
|
||||||
|
|
||||||
|
C_SUB( scratch[5] , *Fout, scratch[1] );
|
||||||
|
C_ADDTO(*Fout, scratch[1]);
|
||||||
|
C_ADD( scratch[3] , scratch[0] , scratch[2] );
|
||||||
|
C_SUB( scratch[4] , scratch[0] , scratch[2] );
|
||||||
|
C_SUB( Fout[m2], *Fout, scratch[3] );
|
||||||
|
tw1 += fstride;
|
||||||
|
tw2 += fstride*2;
|
||||||
|
tw3 += fstride*3;
|
||||||
|
C_ADDTO( *Fout , scratch[3] );
|
||||||
|
|
||||||
|
Fout[m].r = ADD32_ovflw(scratch[5].r, scratch[4].i);
|
||||||
|
Fout[m].i = SUB32_ovflw(scratch[5].i, scratch[4].r);
|
||||||
|
Fout[m3].r = SUB32_ovflw(scratch[5].r, scratch[4].i);
|
||||||
|
Fout[m3].i = ADD32_ovflw(scratch[5].i, scratch[4].r);
|
||||||
|
++Fout;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef RADIX_TWO_ONLY
|
||||||
|
|
||||||
|
static void kf_bfly3(
|
||||||
|
kiss_fft_cpx * Fout,
|
||||||
|
const size_t fstride,
|
||||||
|
const kiss_fft_state *st,
|
||||||
|
int m,
|
||||||
|
int N,
|
||||||
|
int mm
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
size_t k;
|
||||||
|
const size_t m2 = 2*m;
|
||||||
|
const kiss_twiddle_cpx *tw1,*tw2;
|
||||||
|
kiss_fft_cpx scratch[5];
|
||||||
|
kiss_twiddle_cpx epi3;
|
||||||
|
|
||||||
|
kiss_fft_cpx * Fout_beg = Fout;
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
/*epi3.r = -16384;*/ /* Unused */
|
||||||
|
epi3.i = -28378;
|
||||||
|
#else
|
||||||
|
epi3 = st->twiddles[fstride*m];
|
||||||
|
#endif
|
||||||
|
for (i=0;i<N;i++)
|
||||||
|
{
|
||||||
|
Fout = Fout_beg + i*mm;
|
||||||
|
tw1=tw2=st->twiddles;
|
||||||
|
/* For non-custom modes, m is guaranteed to be a multiple of 4. */
|
||||||
|
k=m;
|
||||||
|
do {
|
||||||
|
|
||||||
|
C_MUL(scratch[1],Fout[m] , *tw1);
|
||||||
|
C_MUL(scratch[2],Fout[m2] , *tw2);
|
||||||
|
|
||||||
|
C_ADD(scratch[3],scratch[1],scratch[2]);
|
||||||
|
C_SUB(scratch[0],scratch[1],scratch[2]);
|
||||||
|
tw1 += fstride;
|
||||||
|
tw2 += fstride*2;
|
||||||
|
|
||||||
|
Fout[m].r = SUB32_ovflw(Fout->r, HALF_OF(scratch[3].r));
|
||||||
|
Fout[m].i = SUB32_ovflw(Fout->i, HALF_OF(scratch[3].i));
|
||||||
|
|
||||||
|
C_MULBYSCALAR( scratch[0] , epi3.i );
|
||||||
|
|
||||||
|
C_ADDTO(*Fout,scratch[3]);
|
||||||
|
|
||||||
|
Fout[m2].r = ADD32_ovflw(Fout[m].r, scratch[0].i);
|
||||||
|
Fout[m2].i = SUB32_ovflw(Fout[m].i, scratch[0].r);
|
||||||
|
|
||||||
|
Fout[m].r = SUB32_ovflw(Fout[m].r, scratch[0].i);
|
||||||
|
Fout[m].i = ADD32_ovflw(Fout[m].i, scratch[0].r);
|
||||||
|
|
||||||
|
++Fout;
|
||||||
|
} while(--k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef OVERRIDE_kf_bfly5
|
||||||
|
static void kf_bfly5(
|
||||||
|
kiss_fft_cpx * Fout,
|
||||||
|
const size_t fstride,
|
||||||
|
const kiss_fft_state *st,
|
||||||
|
int m,
|
||||||
|
int N,
|
||||||
|
int mm
|
||||||
|
)
|
||||||
|
{
|
||||||
|
kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4;
|
||||||
|
int i, u;
|
||||||
|
kiss_fft_cpx scratch[13];
|
||||||
|
const kiss_twiddle_cpx *tw;
|
||||||
|
kiss_twiddle_cpx ya,yb;
|
||||||
|
kiss_fft_cpx * Fout_beg = Fout;
|
||||||
|
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
ya.r = 10126;
|
||||||
|
ya.i = -31164;
|
||||||
|
yb.r = -26510;
|
||||||
|
yb.i = -19261;
|
||||||
|
#else
|
||||||
|
ya = st->twiddles[fstride*m];
|
||||||
|
yb = st->twiddles[fstride*2*m];
|
||||||
|
#endif
|
||||||
|
tw=st->twiddles;
|
||||||
|
|
||||||
|
for (i=0;i<N;i++)
|
||||||
|
{
|
||||||
|
Fout = Fout_beg + i*mm;
|
||||||
|
Fout0=Fout;
|
||||||
|
Fout1=Fout0+m;
|
||||||
|
Fout2=Fout0+2*m;
|
||||||
|
Fout3=Fout0+3*m;
|
||||||
|
Fout4=Fout0+4*m;
|
||||||
|
|
||||||
|
/* For non-custom modes, m is guaranteed to be a multiple of 4. */
|
||||||
|
for ( u=0; u<m; ++u ) {
|
||||||
|
scratch[0] = *Fout0;
|
||||||
|
|
||||||
|
C_MUL(scratch[1] ,*Fout1, tw[u*fstride]);
|
||||||
|
C_MUL(scratch[2] ,*Fout2, tw[2*u*fstride]);
|
||||||
|
C_MUL(scratch[3] ,*Fout3, tw[3*u*fstride]);
|
||||||
|
C_MUL(scratch[4] ,*Fout4, tw[4*u*fstride]);
|
||||||
|
|
||||||
|
C_ADD( scratch[7],scratch[1],scratch[4]);
|
||||||
|
C_SUB( scratch[10],scratch[1],scratch[4]);
|
||||||
|
C_ADD( scratch[8],scratch[2],scratch[3]);
|
||||||
|
C_SUB( scratch[9],scratch[2],scratch[3]);
|
||||||
|
|
||||||
|
Fout0->r = ADD32_ovflw(Fout0->r, ADD32_ovflw(scratch[7].r, scratch[8].r));
|
||||||
|
Fout0->i = ADD32_ovflw(Fout0->i, ADD32_ovflw(scratch[7].i, scratch[8].i));
|
||||||
|
|
||||||
|
scratch[5].r = ADD32_ovflw(scratch[0].r, ADD32_ovflw(S_MUL(scratch[7].r,ya.r), S_MUL(scratch[8].r,yb.r)));
|
||||||
|
scratch[5].i = ADD32_ovflw(scratch[0].i, ADD32_ovflw(S_MUL(scratch[7].i,ya.r), S_MUL(scratch[8].i,yb.r)));
|
||||||
|
|
||||||
|
scratch[6].r = ADD32_ovflw(S_MUL(scratch[10].i,ya.i), S_MUL(scratch[9].i,yb.i));
|
||||||
|
scratch[6].i = NEG32_ovflw(ADD32_ovflw(S_MUL(scratch[10].r,ya.i), S_MUL(scratch[9].r,yb.i)));
|
||||||
|
|
||||||
|
C_SUB(*Fout1,scratch[5],scratch[6]);
|
||||||
|
C_ADD(*Fout4,scratch[5],scratch[6]);
|
||||||
|
|
||||||
|
scratch[11].r = ADD32_ovflw(scratch[0].r, ADD32_ovflw(S_MUL(scratch[7].r,yb.r), S_MUL(scratch[8].r,ya.r)));
|
||||||
|
scratch[11].i = ADD32_ovflw(scratch[0].i, ADD32_ovflw(S_MUL(scratch[7].i,yb.r), S_MUL(scratch[8].i,ya.r)));
|
||||||
|
scratch[12].r = SUB32_ovflw(S_MUL(scratch[9].i,ya.i), S_MUL(scratch[10].i,yb.i));
|
||||||
|
scratch[12].i = SUB32_ovflw(S_MUL(scratch[10].r,yb.i), S_MUL(scratch[9].r,ya.i));
|
||||||
|
|
||||||
|
C_ADD(*Fout2,scratch[11],scratch[12]);
|
||||||
|
C_SUB(*Fout3,scratch[11],scratch[12]);
|
||||||
|
|
||||||
|
++Fout0;++Fout1;++Fout2;++Fout3;++Fout4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* OVERRIDE_kf_bfly5 */
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CUSTOM_MODES
|
||||||
|
|
||||||
|
static
|
||||||
|
void compute_bitrev_table(
|
||||||
|
int Fout,
|
||||||
|
opus_int32 *f,
|
||||||
|
const size_t fstride,
|
||||||
|
int in_stride,
|
||||||
|
opus_int16 * factors,
|
||||||
|
const kiss_fft_state *st
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const int p=*factors++; /* the radix */
|
||||||
|
const int m=*factors++; /* stage's fft length/p */
|
||||||
|
|
||||||
|
/*printf ("fft %d %d %d %d %d %d\n", p*m, m, p, s2, fstride*in_stride, N);*/
|
||||||
|
if (m==1)
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
for (j=0;j<p;j++)
|
||||||
|
{
|
||||||
|
*f = Fout+j;
|
||||||
|
f += fstride*in_stride;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int j;
|
||||||
|
for (j=0;j<p;j++)
|
||||||
|
{
|
||||||
|
compute_bitrev_table( Fout , f, fstride*p, in_stride, factors,st);
|
||||||
|
f += fstride*in_stride;
|
||||||
|
Fout += m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* facbuf is populated by p1,m1,p2,m2, ...
|
||||||
|
where
|
||||||
|
p[i] * m[i] = m[i-1]
|
||||||
|
m0 = n */
|
||||||
|
static
|
||||||
|
int kf_factor(int n,opus_int16 * facbuf)
|
||||||
|
{
|
||||||
|
int p=4;
|
||||||
|
int i;
|
||||||
|
int stages=0;
|
||||||
|
int nbak = n;
|
||||||
|
|
||||||
|
/*factor out powers of 4, powers of 2, then any remaining primes */
|
||||||
|
do {
|
||||||
|
while (n % p) {
|
||||||
|
switch (p) {
|
||||||
|
case 4: p = 2; break;
|
||||||
|
case 2: p = 3; break;
|
||||||
|
default: p += 2; break;
|
||||||
|
}
|
||||||
|
if (p>32000 || (opus_int32)p*(opus_int32)p > n)
|
||||||
|
p = n; /* no more factors, skip to end */
|
||||||
|
}
|
||||||
|
n /= p;
|
||||||
|
#ifdef RADIX_TWO_ONLY
|
||||||
|
if (p!=2 && p != 4)
|
||||||
|
#else
|
||||||
|
if (p>5)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
facbuf[2*stages] = p;
|
||||||
|
if (p==2 && stages > 1)
|
||||||
|
{
|
||||||
|
facbuf[2*stages] = 4;
|
||||||
|
facbuf[2] = 2;
|
||||||
|
}
|
||||||
|
stages++;
|
||||||
|
} while (n > 1);
|
||||||
|
n = nbak;
|
||||||
|
/* Reverse the order to get the radix 4 at the end, so we can use the
|
||||||
|
fast degenerate case. It turns out that reversing the order also
|
||||||
|
improves the noise behaviour. */
|
||||||
|
for (i=0;i<stages/2;i++)
|
||||||
|
{
|
||||||
|
int tmp;
|
||||||
|
tmp = facbuf[2*i];
|
||||||
|
facbuf[2*i] = facbuf[2*(stages-i-1)];
|
||||||
|
facbuf[2*(stages-i-1)] = tmp;
|
||||||
|
}
|
||||||
|
for (i=0;i<stages;i++)
|
||||||
|
{
|
||||||
|
n /= facbuf[2*i];
|
||||||
|
facbuf[2*i+1] = n;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void compute_twiddles(kiss_twiddle_cpx *twiddles, int nfft)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
for (i=0;i<nfft;++i) {
|
||||||
|
opus_val32 phase = -i;
|
||||||
|
kf_cexp2(twiddles+i, DIV32(SHL32(phase,17),nfft));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
for (i=0;i<nfft;++i) {
|
||||||
|
const double pi=3.14159265358979323846264338327;
|
||||||
|
double phase = ( -2*pi /nfft ) * i;
|
||||||
|
kf_cexp(twiddles+i, phase );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int rnn_fft_alloc_arch_c(kiss_fft_state *st) {
|
||||||
|
(void)st;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Allocates all necessary storage space for the fft and ifft.
|
||||||
|
* The return value is a contiguous block of memory. As such,
|
||||||
|
* It can be freed with free().
|
||||||
|
* */
|
||||||
|
kiss_fft_state *rnn_fft_alloc_twiddles(int nfft,void * mem,size_t * lenmem,
|
||||||
|
const kiss_fft_state *base, int arch)
|
||||||
|
{
|
||||||
|
kiss_fft_state *st=NULL;
|
||||||
|
size_t memneeded = sizeof(struct kiss_fft_state); /* twiddle factors*/
|
||||||
|
|
||||||
|
if ( lenmem==NULL ) {
|
||||||
|
st = ( kiss_fft_state*)KISS_FFT_MALLOC( memneeded );
|
||||||
|
}else{
|
||||||
|
if (mem != NULL && *lenmem >= memneeded)
|
||||||
|
st = (kiss_fft_state*)mem;
|
||||||
|
*lenmem = memneeded;
|
||||||
|
}
|
||||||
|
if (st) {
|
||||||
|
opus_int32 *bitrev;
|
||||||
|
kiss_twiddle_cpx *twiddles;
|
||||||
|
|
||||||
|
st->nfft=nfft;
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
st->scale_shift = celt_ilog2(st->nfft);
|
||||||
|
if (st->nfft == 1<<st->scale_shift)
|
||||||
|
st->scale = Q15ONE;
|
||||||
|
else
|
||||||
|
st->scale = (1073741824+st->nfft/2)/st->nfft>>(15-st->scale_shift);
|
||||||
|
#else
|
||||||
|
st->scale = 1.f/nfft;
|
||||||
|
#endif
|
||||||
|
if (base != NULL)
|
||||||
|
{
|
||||||
|
st->twiddles = base->twiddles;
|
||||||
|
st->shift = 0;
|
||||||
|
while (st->shift < 32 && nfft<<st->shift != base->nfft)
|
||||||
|
st->shift++;
|
||||||
|
if (st->shift>=32)
|
||||||
|
goto fail;
|
||||||
|
} else {
|
||||||
|
st->twiddles = twiddles = (kiss_twiddle_cpx*)KISS_FFT_MALLOC(sizeof(kiss_twiddle_cpx)*nfft);
|
||||||
|
compute_twiddles(twiddles, nfft);
|
||||||
|
st->shift = -1;
|
||||||
|
}
|
||||||
|
if (!kf_factor(nfft,st->factors))
|
||||||
|
{
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* bitrev */
|
||||||
|
st->bitrev = bitrev = (opus_int32*)KISS_FFT_MALLOC(sizeof(opus_int32)*nfft);
|
||||||
|
if (st->bitrev==NULL)
|
||||||
|
goto fail;
|
||||||
|
compute_bitrev_table(0, bitrev, 1,1, st->factors,st);
|
||||||
|
|
||||||
|
/* Initialize architecture specific fft parameters */
|
||||||
|
if (rnn_fft_alloc_arch(st, arch))
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
return st;
|
||||||
|
fail:
|
||||||
|
rnn_fft_free(st, arch);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
kiss_fft_state *rnn_fft_alloc(int nfft,void * mem,size_t * lenmem, int arch)
|
||||||
|
{
|
||||||
|
return rnn_fft_alloc_twiddles(nfft, mem, lenmem, NULL, arch);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rnn_fft_free_arch_c(kiss_fft_state *st) {
|
||||||
|
(void)st;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rnn_fft_free(const kiss_fft_state *cfg, int arch)
|
||||||
|
{
|
||||||
|
if (cfg)
|
||||||
|
{
|
||||||
|
rnn_fft_free_arch((kiss_fft_state *)cfg, arch);
|
||||||
|
opus_free((opus_int32*)cfg->bitrev);
|
||||||
|
if (cfg->shift < 0)
|
||||||
|
opus_free((kiss_twiddle_cpx*)cfg->twiddles);
|
||||||
|
opus_free((kiss_fft_state*)cfg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CUSTOM_MODES */
|
||||||
|
|
||||||
|
void rnn_fft_impl(const kiss_fft_state *st,kiss_fft_cpx *fout)
|
||||||
|
{
|
||||||
|
int m2, m;
|
||||||
|
int p;
|
||||||
|
int L;
|
||||||
|
int fstride[MAXFACTORS];
|
||||||
|
int i;
|
||||||
|
int shift;
|
||||||
|
|
||||||
|
/* st->shift can be -1 */
|
||||||
|
shift = st->shift>0 ? st->shift : 0;
|
||||||
|
|
||||||
|
fstride[0] = 1;
|
||||||
|
L=0;
|
||||||
|
do {
|
||||||
|
p = st->factors[2*L];
|
||||||
|
m = st->factors[2*L+1];
|
||||||
|
fstride[L+1] = fstride[L]*p;
|
||||||
|
L++;
|
||||||
|
} while(m!=1);
|
||||||
|
m = st->factors[2*L-1];
|
||||||
|
for (i=L-1;i>=0;i--)
|
||||||
|
{
|
||||||
|
if (i!=0)
|
||||||
|
m2 = st->factors[2*i-1];
|
||||||
|
else
|
||||||
|
m2 = 1;
|
||||||
|
switch (st->factors[2*i])
|
||||||
|
{
|
||||||
|
case 2:
|
||||||
|
kf_bfly2(fout, m, fstride[i]);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
kf_bfly4(fout,fstride[i]<<shift,st,m, fstride[i], m2);
|
||||||
|
break;
|
||||||
|
#ifndef RADIX_TWO_ONLY
|
||||||
|
case 3:
|
||||||
|
kf_bfly3(fout,fstride[i]<<shift,st,m, fstride[i], m2);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
kf_bfly5(fout,fstride[i]<<shift,st,m, fstride[i], m2);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
m = m2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rnn_fft_c(const kiss_fft_state *st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
opus_val16 scale;
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
/* Allows us to scale with MULT16_32_Q16(), which is faster than
|
||||||
|
MULT16_32_Q15() on ARM. */
|
||||||
|
int scale_shift = st->scale_shift-1;
|
||||||
|
#endif
|
||||||
|
scale = st->scale;
|
||||||
|
|
||||||
|
celt_assert2 (fin != fout, "In-place FFT not supported");
|
||||||
|
/* Bit-reverse the input */
|
||||||
|
for (i=0;i<st->nfft;i++)
|
||||||
|
{
|
||||||
|
kiss_fft_cpx x = fin[i];
|
||||||
|
fout[st->bitrev[i]].r = SHR32(MULT16_32_Q16(scale, x.r), scale_shift);
|
||||||
|
fout[st->bitrev[i]].i = SHR32(MULT16_32_Q16(scale, x.i), scale_shift);
|
||||||
|
}
|
||||||
|
rnn_fft_impl(st, fout);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void rnn_ifft_c(const kiss_fft_state *st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
celt_assert2 (fin != fout, "In-place FFT not supported");
|
||||||
|
/* Bit-reverse the input */
|
||||||
|
for (i=0;i<st->nfft;i++)
|
||||||
|
fout[st->bitrev[i]] = fin[i];
|
||||||
|
for (i=0;i<st->nfft;i++)
|
||||||
|
fout[i].i = -fout[i].i;
|
||||||
|
rnn_fft_impl(st, fout);
|
||||||
|
for (i=0;i<st->nfft;i++)
|
||||||
|
fout[i].i = -fout[i].i;
|
||||||
|
}
|
||||||
203
third_party/rnnoise/src/kiss_fft.h
vendored
Normal file
203
third_party/rnnoise/src/kiss_fft.h
vendored
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
/*Copyright (c) 2003-2004, Mark Borgerding
|
||||||
|
Lots of modifications by Jean-Marc Valin
|
||||||
|
Copyright (c) 2005-2007, Xiph.Org Foundation
|
||||||
|
Copyright (c) 2008, Xiph.Org Foundation, CSIRO
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.*/
|
||||||
|
|
||||||
|
#ifndef KISS_FFT_H
|
||||||
|
#define KISS_FFT_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "arch.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#define opus_alloc(x) malloc(x)
|
||||||
|
#define opus_free(x) free(x)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_SIMD
|
||||||
|
# include <xmmintrin.h>
|
||||||
|
# define kiss_fft_scalar __m128
|
||||||
|
#define KISS_FFT_MALLOC(nbytes) memalign(16,nbytes)
|
||||||
|
#else
|
||||||
|
#define KISS_FFT_MALLOC opus_alloc
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
#include "arch.h"
|
||||||
|
|
||||||
|
# define kiss_fft_scalar opus_int32
|
||||||
|
# define kiss_twiddle_scalar opus_int16
|
||||||
|
|
||||||
|
|
||||||
|
#else
|
||||||
|
# ifndef kiss_fft_scalar
|
||||||
|
/* default is float */
|
||||||
|
# define kiss_fft_scalar float
|
||||||
|
# define kiss_twiddle_scalar float
|
||||||
|
# define KF_SUFFIX _celt_single
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
kiss_fft_scalar r;
|
||||||
|
kiss_fft_scalar i;
|
||||||
|
}kiss_fft_cpx;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
kiss_twiddle_scalar r;
|
||||||
|
kiss_twiddle_scalar i;
|
||||||
|
}kiss_twiddle_cpx;
|
||||||
|
|
||||||
|
#define MAXFACTORS 8
|
||||||
|
/* e.g. an fft of length 128 has 4 factors
|
||||||
|
as far as kissfft is concerned
|
||||||
|
4*4*4*2
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct arch_fft_state{
|
||||||
|
int is_supported;
|
||||||
|
void *priv;
|
||||||
|
} arch_fft_state;
|
||||||
|
|
||||||
|
typedef struct kiss_fft_state{
|
||||||
|
int nfft;
|
||||||
|
opus_val16 scale;
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
int scale_shift;
|
||||||
|
#endif
|
||||||
|
int shift;
|
||||||
|
opus_int16 factors[2*MAXFACTORS];
|
||||||
|
const opus_int32 *bitrev;
|
||||||
|
const kiss_twiddle_cpx *twiddles;
|
||||||
|
arch_fft_state *arch_fft;
|
||||||
|
} kiss_fft_state;
|
||||||
|
|
||||||
|
#if defined(HAVE_ARM_NE10)
|
||||||
|
#include "arm/fft_arm.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*typedef struct kiss_fft_state* kiss_fft_cfg;*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* opus_fft_alloc
|
||||||
|
*
|
||||||
|
* Initialize a FFT (or IFFT) algorithm's cfg/state buffer.
|
||||||
|
*
|
||||||
|
* typical usage: kiss_fft_cfg mycfg=opus_fft_alloc(1024,0,NULL,NULL);
|
||||||
|
*
|
||||||
|
* The return value from fft_alloc is a cfg buffer used internally
|
||||||
|
* by the fft routine or NULL.
|
||||||
|
*
|
||||||
|
* If lenmem is NULL, then opus_fft_alloc will allocate a cfg buffer using malloc.
|
||||||
|
* The returned value should be free()d when done to avoid memory leaks.
|
||||||
|
*
|
||||||
|
* The state can be placed in a user supplied buffer 'mem':
|
||||||
|
* If lenmem is not NULL and mem is not NULL and *lenmem is large enough,
|
||||||
|
* then the function places the cfg in mem and the size used in *lenmem
|
||||||
|
* and returns mem.
|
||||||
|
*
|
||||||
|
* If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough),
|
||||||
|
* then the function returns NULL and places the minimum cfg
|
||||||
|
* buffer size in *lenmem.
|
||||||
|
* */
|
||||||
|
|
||||||
|
kiss_fft_state *rnn_fft_alloc_twiddles(int nfft,void * mem,size_t * lenmem, const kiss_fft_state *base, int arch);
|
||||||
|
|
||||||
|
kiss_fft_state *rnn_fft_alloc(int nfft,void * mem,size_t * lenmem, int arch);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* opus_fft(cfg,in_out_buf)
|
||||||
|
*
|
||||||
|
* Perform an FFT on a complex input buffer.
|
||||||
|
* for a forward FFT,
|
||||||
|
* fin should be f[0] , f[1] , ... ,f[nfft-1]
|
||||||
|
* fout will be F[0] , F[1] , ... ,F[nfft-1]
|
||||||
|
* Note that each element is complex and can be accessed like
|
||||||
|
f[k].r and f[k].i
|
||||||
|
* */
|
||||||
|
void rnn_fft_c(const kiss_fft_state *cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout);
|
||||||
|
void rnn_ifft_c(const kiss_fft_state *cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout);
|
||||||
|
|
||||||
|
void rnn_fft_impl(const kiss_fft_state *st,kiss_fft_cpx *fout);
|
||||||
|
void rnn_ifft_impl(const kiss_fft_state *st,kiss_fft_cpx *fout);
|
||||||
|
|
||||||
|
void rnn_fft_free(const kiss_fft_state *cfg, int arch);
|
||||||
|
|
||||||
|
|
||||||
|
void rnn_fft_free_arch_c(kiss_fft_state *st);
|
||||||
|
int rnn_fft_alloc_arch_c(kiss_fft_state *st);
|
||||||
|
|
||||||
|
#if !defined(OVERRIDE_OPUS_FFT)
|
||||||
|
/* Is run-time CPU detection enabled on this platform? */
|
||||||
|
#if defined(OPUS_HAVE_RTCD) && (defined(HAVE_ARM_NE10))
|
||||||
|
|
||||||
|
extern int (*const OPUS_FFT_ALLOC_ARCH_IMPL[OPUS_ARCHMASK+1])(
|
||||||
|
kiss_fft_state *st);
|
||||||
|
|
||||||
|
#define opus_fft_alloc_arch(_st, arch) \
|
||||||
|
((*OPUS_FFT_ALLOC_ARCH_IMPL[(arch)&OPUS_ARCHMASK])(_st))
|
||||||
|
|
||||||
|
extern void (*const OPUS_FFT_FREE_ARCH_IMPL[OPUS_ARCHMASK+1])(
|
||||||
|
kiss_fft_state *st);
|
||||||
|
#define opus_fft_free_arch(_st, arch) \
|
||||||
|
((*OPUS_FFT_FREE_ARCH_IMPL[(arch)&OPUS_ARCHMASK])(_st))
|
||||||
|
|
||||||
|
extern void (*const OPUS_FFT[OPUS_ARCHMASK+1])(const kiss_fft_state *cfg,
|
||||||
|
const kiss_fft_cpx *fin, kiss_fft_cpx *fout);
|
||||||
|
#define opus_fft(_cfg, _fin, _fout, arch) \
|
||||||
|
((*OPUS_FFT[(arch)&OPUS_ARCHMASK])(_cfg, _fin, _fout))
|
||||||
|
|
||||||
|
extern void (*const OPUS_IFFT[OPUS_ARCHMASK+1])(const kiss_fft_state *cfg,
|
||||||
|
const kiss_fft_cpx *fin, kiss_fft_cpx *fout);
|
||||||
|
#define opus_ifft(_cfg, _fin, _fout, arch) \
|
||||||
|
((*OPUS_IFFT[(arch)&OPUS_ARCHMASK])(_cfg, _fin, _fout))
|
||||||
|
|
||||||
|
#else /* else for if defined(OPUS_HAVE_RTCD) && (defined(HAVE_ARM_NE10)) */
|
||||||
|
|
||||||
|
#define rnn_fft_alloc_arch(_st, arch) \
|
||||||
|
((void)(arch), rnn_fft_alloc_arch_c(_st))
|
||||||
|
|
||||||
|
#define rnn_fft_free_arch(_st, arch) \
|
||||||
|
((void)(arch), rnn_fft_free_arch_c(_st))
|
||||||
|
|
||||||
|
#define rnn_fft(_cfg, _fin, _fout, arch) \
|
||||||
|
((void)(arch), rnn_fft_c(_cfg, _fin, _fout))
|
||||||
|
|
||||||
|
#define rnn_ifft(_cfg, _fin, _fout, arch) \
|
||||||
|
((void)(arch), rnn_ifft_c(_cfg, _fin, _fout))
|
||||||
|
|
||||||
|
#endif /* end if defined(OPUS_HAVE_RTCD) && (defined(HAVE_ARM_NE10)) */
|
||||||
|
#endif /* end if !defined(OVERRIDE_OPUS_FFT) */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
123
third_party/rnnoise/src/nnet.c
vendored
Normal file
123
third_party/rnnoise/src/nnet.c
vendored
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
/* Copyright (c) 2018 Mozilla
|
||||||
|
2008-2011 Octasic Inc.
|
||||||
|
2012-2017 Jean-Marc Valin */
|
||||||
|
/*
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
- Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||||||
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "opus_types.h"
|
||||||
|
#include "arch.h"
|
||||||
|
#include "nnet.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "vec.h"
|
||||||
|
|
||||||
|
#ifdef ENABLE_OSCE
|
||||||
|
#include "osce.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef NO_OPTIMIZATIONS
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#pragma message ("Compiling without any vectorization. This code will be very slow")
|
||||||
|
#else
|
||||||
|
#warning Compiling without any vectorization. This code will be very slow
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define SOFTMAX_HACK
|
||||||
|
|
||||||
|
|
||||||
|
void compute_generic_dense(const LinearLayer *layer, float *output, const float *input, int activation, int arch)
|
||||||
|
{
|
||||||
|
compute_linear(layer, output, input, arch);
|
||||||
|
compute_activation(output, output, layer->nb_outputs, activation, arch);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAX_RNN_NEURONS_ALL 1024
|
||||||
|
|
||||||
|
void compute_generic_gru(const LinearLayer *input_weights, const LinearLayer *recurrent_weights, float *state, const float *in, int arch)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int N;
|
||||||
|
float zrh[3*MAX_RNN_NEURONS_ALL];
|
||||||
|
float recur[3*MAX_RNN_NEURONS_ALL];
|
||||||
|
float *z;
|
||||||
|
float *r;
|
||||||
|
float *h;
|
||||||
|
celt_assert(3*recurrent_weights->nb_inputs == recurrent_weights->nb_outputs);
|
||||||
|
celt_assert(input_weights->nb_outputs == recurrent_weights->nb_outputs);
|
||||||
|
N = recurrent_weights->nb_inputs;
|
||||||
|
z = zrh;
|
||||||
|
r = &zrh[N];
|
||||||
|
h = &zrh[2*N];
|
||||||
|
celt_assert(recurrent_weights->nb_outputs <= 3*MAX_RNN_NEURONS_ALL);
|
||||||
|
celt_assert(in != state);
|
||||||
|
compute_linear(input_weights, zrh, in, arch);
|
||||||
|
compute_linear(recurrent_weights, recur, state, arch);
|
||||||
|
for (i=0;i<2*N;i++)
|
||||||
|
zrh[i] += recur[i];
|
||||||
|
compute_activation(zrh, zrh, 2*N, ACTIVATION_SIGMOID, arch);
|
||||||
|
for (i=0;i<N;i++)
|
||||||
|
h[i] += recur[2*N+i]*r[i];
|
||||||
|
compute_activation(h, h, N, ACTIVATION_TANH, arch);
|
||||||
|
for (i=0;i<N;i++)
|
||||||
|
h[i] = z[i]*state[i] + (1-z[i])*h[i];
|
||||||
|
for (i=0;i<N;i++)
|
||||||
|
state[i] = h[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
void compute_glu(const LinearLayer *layer, float *output, const float *input, int arch)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
float act2[MAX_INPUTS];
|
||||||
|
celt_assert(layer->nb_inputs == layer->nb_outputs);
|
||||||
|
compute_linear(layer, act2, input, arch);
|
||||||
|
compute_activation(act2, act2, layer->nb_outputs, ACTIVATION_SIGMOID, arch);
|
||||||
|
if (input == output) {
|
||||||
|
/* Give a vectorization hint to the compiler for the in-place case. */
|
||||||
|
for (i=0;i<layer->nb_outputs;i++) output[i] = output[i]*act2[i];
|
||||||
|
} else {
|
||||||
|
for (i=0;i<layer->nb_outputs;i++) output[i] = input[i]*act2[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAX_CONV_INPUTS_ALL 1024
|
||||||
|
|
||||||
|
void compute_generic_conv1d(const LinearLayer *layer, float *output, float *mem, const float *input, int input_size, int activation, int arch)
|
||||||
|
{
|
||||||
|
float tmp[MAX_CONV_INPUTS_ALL];
|
||||||
|
celt_assert(input != output);
|
||||||
|
celt_assert(layer->nb_inputs <= MAX_CONV_INPUTS_ALL);
|
||||||
|
if (layer->nb_inputs!=input_size) RNN_COPY(tmp, mem, layer->nb_inputs-input_size);
|
||||||
|
RNN_COPY(&tmp[layer->nb_inputs-input_size], input, input_size);
|
||||||
|
compute_linear(layer, output, tmp, arch);
|
||||||
|
compute_activation(output, output, layer->nb_outputs, activation, arch);
|
||||||
|
if (layer->nb_inputs!=input_size) RNN_COPY(mem, &tmp[input_size], layer->nb_inputs-input_size);
|
||||||
|
}
|
||||||
169
third_party/rnnoise/src/nnet.h
vendored
Normal file
169
third_party/rnnoise/src/nnet.h
vendored
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
/* Copyright (c) 2018 Mozilla
|
||||||
|
Copyright (c) 2017 Jean-Marc Valin */
|
||||||
|
/*
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
- Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||||||
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef NNET_H_
|
||||||
|
#define NNET_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "opus_types.h"
|
||||||
|
|
||||||
|
#define ACTIVATION_LINEAR 0
|
||||||
|
#define ACTIVATION_SIGMOID 1
|
||||||
|
#define ACTIVATION_TANH 2
|
||||||
|
#define ACTIVATION_RELU 3
|
||||||
|
#define ACTIVATION_SOFTMAX 4
|
||||||
|
#define ACTIVATION_SWISH 5
|
||||||
|
|
||||||
|
#define WEIGHT_BLOB_VERSION 0
|
||||||
|
#define WEIGHT_BLOCK_SIZE 64
|
||||||
|
typedef struct {
|
||||||
|
const char *name;
|
||||||
|
int type;
|
||||||
|
int size;
|
||||||
|
const void *data;
|
||||||
|
} WeightArray;
|
||||||
|
|
||||||
|
#define WEIGHT_TYPE_float 0
|
||||||
|
#define WEIGHT_TYPE_int 1
|
||||||
|
#define WEIGHT_TYPE_qweight 2
|
||||||
|
#define WEIGHT_TYPE_int8 3
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char head[4];
|
||||||
|
int version;
|
||||||
|
int type;
|
||||||
|
int size;
|
||||||
|
int block_size;
|
||||||
|
char name[44];
|
||||||
|
} WeightHead;
|
||||||
|
|
||||||
|
/* Generic sparse affine transformation. */
|
||||||
|
typedef struct {
|
||||||
|
const float *bias;
|
||||||
|
const float *subias;
|
||||||
|
const opus_int8 *weights;
|
||||||
|
const float *float_weights;
|
||||||
|
const int *weights_idx;
|
||||||
|
const float *diag;
|
||||||
|
const float *scale;
|
||||||
|
int nb_inputs;
|
||||||
|
int nb_outputs;
|
||||||
|
} LinearLayer;
|
||||||
|
|
||||||
|
/* Generic sparse affine transformation. */
|
||||||
|
typedef struct {
|
||||||
|
const float *bias;
|
||||||
|
const float *float_weights;
|
||||||
|
int in_channels;
|
||||||
|
int out_channels;
|
||||||
|
int ktime;
|
||||||
|
int kheight;
|
||||||
|
} Conv2dLayer;
|
||||||
|
|
||||||
|
|
||||||
|
/* Changes some symbol names to add the rnn_ prefix so we don't get conflicts with Opus. */
|
||||||
|
#define linear_init rnn_linear_init
|
||||||
|
#define conv2d_init rnn_conv2d_init
|
||||||
|
#define compute_generic_dense rnn_compute_generic_dense
|
||||||
|
#define compute_generic_gru rnn_compute_generic_gru
|
||||||
|
#define compute_generic_conv1d rnn_compute_generic_conv1d
|
||||||
|
#define compute_glu rnn_compute_glu
|
||||||
|
|
||||||
|
#define parse_weights rnn_parse_weights
|
||||||
|
|
||||||
|
#define compute_linear_c rnn_compute_linear_c
|
||||||
|
#define compute_activation_c rnn_compute_activation_c
|
||||||
|
#define compute_conv2d_c rnn_compute_conv2d_c
|
||||||
|
#define compute_linear_sse4_1 rnn_compute_linear_sse4_1
|
||||||
|
#define compute_activation_sse4_1 rnn_compute_activation_sse4_1
|
||||||
|
#define compute_conv2d_sse4_1 rnn_compute_conv2d_sse4_1
|
||||||
|
#define compute_linear_avx2 rnn_compute_linear_avx2
|
||||||
|
#define compute_activation_avx2 rnn_compute_activation_avx2
|
||||||
|
#define compute_conv2d_avx2 rnn_compute_conv2d_avx2
|
||||||
|
|
||||||
|
|
||||||
|
void compute_generic_dense(const LinearLayer *layer, float *output, const float *input, int activation, int arch);
|
||||||
|
void compute_generic_gru(const LinearLayer *input_weights, const LinearLayer *recurrent_weights, float *state, const float *in, int arch);
|
||||||
|
void compute_generic_conv1d(const LinearLayer *layer, float *output, float *mem, const float *input, int input_size, int activation, int arch);
|
||||||
|
void compute_glu(const LinearLayer *layer, float *output, const float *input, int arch);
|
||||||
|
|
||||||
|
|
||||||
|
int parse_weights(WeightArray **list, const void *data, int len);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int linear_init(LinearLayer *layer, const WeightArray *arrays,
|
||||||
|
const char *bias,
|
||||||
|
const char *subias,
|
||||||
|
const char *weights,
|
||||||
|
const char *float_weights,
|
||||||
|
const char *weights_idx,
|
||||||
|
const char *diag,
|
||||||
|
const char *scale,
|
||||||
|
int nb_inputs,
|
||||||
|
int nb_outputs);
|
||||||
|
|
||||||
|
int conv2d_init(Conv2dLayer *layer, const WeightArray *arrays,
|
||||||
|
const char *bias,
|
||||||
|
const char *float_weights,
|
||||||
|
int in_channels,
|
||||||
|
int out_channels,
|
||||||
|
int ktime,
|
||||||
|
int kheight);
|
||||||
|
|
||||||
|
|
||||||
|
void compute_linear_c(const LinearLayer *linear, float *out, const float *in);
|
||||||
|
void compute_activation_c(float *output, const float *input, int N, int activation);
|
||||||
|
void compute_conv2d_c(const Conv2dLayer *conv, float *out, float *mem, const float *in, int height, int hstride, int activation);
|
||||||
|
|
||||||
|
#ifdef RNN_ENABLE_X86_RTCD
|
||||||
|
#include "x86/dnn_x86.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef OVERRIDE_COMPUTE_LINEAR
|
||||||
|
#define compute_linear(linear, out, in, arch) ((void)(arch),compute_linear_c(linear, out, in))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef OVERRIDE_COMPUTE_ACTIVATION
|
||||||
|
#define compute_activation(output, input, N, activation, arch) ((void)(arch),compute_activation_c(output, input, N, activation))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef OVERRIDE_COMPUTE_CONV2D
|
||||||
|
#define compute_conv2d(conv, out, mem, in, height, hstride, activation, arch) ((void)(arch),compute_conv2d_c(conv, out, mem, in, height, hstride, activation))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__x86_64__) && !defined(RNN_ENABLE_X86_RTCD) && !defined(__AVX2__)
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#pragma message ("Only SSE and SSE2 are available. On newer machines, enable SSSE3/AVX/AVX2 to get better performance")
|
||||||
|
#else
|
||||||
|
#warning "Only SSE and SSE2 are available. On newer machines, enable SSSE3/AVX/AVX2 using -march= to get better performance"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* NNET_H_ */
|
||||||
257
third_party/rnnoise/src/nnet_arch.h
vendored
Normal file
257
third_party/rnnoise/src/nnet_arch.h
vendored
Normal file
@@ -0,0 +1,257 @@
|
|||||||
|
/* Copyright (c) 2018-2019 Mozilla
|
||||||
|
2023 Amazon */
|
||||||
|
/*
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
- Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||||||
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef NNET_ARCH_H
|
||||||
|
#define NNET_ARCH_H
|
||||||
|
|
||||||
|
#include "nnet.h"
|
||||||
|
#include "arch.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "vec.h"
|
||||||
|
|
||||||
|
#define CAT_SUFFIX2(a,b) a ## b
|
||||||
|
#define CAT_SUFFIX(a,b) CAT_SUFFIX2(a, b)
|
||||||
|
|
||||||
|
#define RTCD_SUF(name) CAT_SUFFIX(name, RTCD_ARCH)
|
||||||
|
|
||||||
|
# if !defined(OPUS_GNUC_PREREQ)
|
||||||
|
# if defined(__GNUC__)&&defined(__GNUC_MINOR__)
|
||||||
|
# define OPUS_GNUC_PREREQ(_maj,_min) \
|
||||||
|
((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min))
|
||||||
|
# else
|
||||||
|
# define OPUS_GNUC_PREREQ(_maj,_min) 0
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Force vectorization on for DNN code because some of the loops rely on
|
||||||
|
compiler vectorization rather than explicitly using intrinsics. */
|
||||||
|
#if OPUS_GNUC_PREREQ(5,1)
|
||||||
|
#define GCC_POP_OPTIONS
|
||||||
|
#pragma GCC push_options
|
||||||
|
#pragma GCC optimize("tree-vectorize")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define MAX_ACTIVATIONS (4096)
|
||||||
|
|
||||||
|
static OPUS_INLINE void vec_swish(float *y, const float *x, int N)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
float tmp[MAX_ACTIVATIONS];
|
||||||
|
celt_assert(N <= MAX_ACTIVATIONS);
|
||||||
|
vec_sigmoid(tmp, x, N);
|
||||||
|
for (i=0;i<N;i++)
|
||||||
|
y[i] = x[i]*tmp[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
static OPUS_INLINE float relu(float x)
|
||||||
|
{
|
||||||
|
return x < 0 ? 0 : x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*#define HIGH_ACCURACY */
|
||||||
|
|
||||||
|
void RTCD_SUF(compute_activation_)(float *output, const float *input, int N, int activation)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if (activation == ACTIVATION_SIGMOID) {
|
||||||
|
#ifdef HIGH_ACCURACY
|
||||||
|
for (int n=0; n<N; n++)
|
||||||
|
{
|
||||||
|
output[n] = 1.f / (1 + exp(-input[n]));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
vec_sigmoid(output, input, N);
|
||||||
|
#endif
|
||||||
|
} else if (activation == ACTIVATION_TANH) {
|
||||||
|
#ifdef HIGH_ACCURACY
|
||||||
|
for (int n=0; n<N; n++)
|
||||||
|
{
|
||||||
|
output[n] = tanh(input[n]);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
vec_tanh(output, input, N);
|
||||||
|
#endif
|
||||||
|
} else if (activation == ACTIVATION_SWISH) {
|
||||||
|
vec_swish(output, input, N);
|
||||||
|
} else if (activation == ACTIVATION_RELU) {
|
||||||
|
for (i=0;i<N;i++)
|
||||||
|
output[i] = relu(input[i]);
|
||||||
|
} else if (activation == ACTIVATION_SOFTMAX) {
|
||||||
|
#ifdef SOFTMAX_HACK
|
||||||
|
RNN_COPY(output, input, N);
|
||||||
|
/*for (i=0;i<N;i++)
|
||||||
|
output[i] = input[i];*/
|
||||||
|
#else
|
||||||
|
float sum = 0;
|
||||||
|
softmax(output, input, N);
|
||||||
|
for (i=0;i<N;i++) {
|
||||||
|
sum += output[i];
|
||||||
|
}
|
||||||
|
sum = 1.f/(sum+1e-30);
|
||||||
|
for (i=0;i<N;i++)
|
||||||
|
output[i] = sum*output[i];
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
celt_assert(activation == ACTIVATION_LINEAR);
|
||||||
|
if (input != output) {
|
||||||
|
for (i=0;i<N;i++)
|
||||||
|
output[i] = input[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RTCD_SUF(compute_linear_) (const LinearLayer *linear, float *out, const float *in)
|
||||||
|
{
|
||||||
|
int i, M, N;
|
||||||
|
const float *bias;
|
||||||
|
celt_assert(in != out);
|
||||||
|
bias = linear->bias;
|
||||||
|
M = linear->nb_inputs;
|
||||||
|
N = linear->nb_outputs;
|
||||||
|
if (linear->float_weights != NULL) {
|
||||||
|
if (linear->weights_idx != NULL) sparse_sgemv8x4(out, linear->float_weights, linear->weights_idx, N, in);
|
||||||
|
else sgemv(out, linear->float_weights, N, M, N, in);
|
||||||
|
} else if (linear->weights != NULL) {
|
||||||
|
if (linear->weights_idx != NULL) sparse_cgemv8x4(out, linear->weights, linear->weights_idx, linear->scale, N, M, in);
|
||||||
|
else cgemv8x4(out, linear->weights, linear->scale, N, M, in);
|
||||||
|
/* Only use SU biases on for integer matrices on SU archs. */
|
||||||
|
#ifdef USE_SU_BIAS
|
||||||
|
bias = linear->subias;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else RNN_CLEAR(out, N);
|
||||||
|
if (bias != NULL) {
|
||||||
|
for (i=0;i<N;i++) out[i] += bias[i];
|
||||||
|
}
|
||||||
|
if (linear->diag) {
|
||||||
|
/* Diag is only used for GRU recurrent weights. */
|
||||||
|
celt_assert(3*M == N);
|
||||||
|
for (i=0;i<M;i++) {
|
||||||
|
out[i] += linear->diag[i]*in[i];
|
||||||
|
out[i+M] += linear->diag[i+M]*in[i];
|
||||||
|
out[i+2*M] += linear->diag[i+2*M]*in[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Computes non-padded convolution for input [ ksize1 x in_channels x (len2+ksize2) ],
|
||||||
|
kernel [ out_channels x in_channels x ksize1 x ksize2 ],
|
||||||
|
storing the output as [ out_channels x len2 ].
|
||||||
|
We assume that the output dimension along the ksize1 axis is 1,
|
||||||
|
i.e. processing one frame at a time. */
|
||||||
|
static void conv2d_float(float *out, const float *weights, int in_channels, int out_channels, int ktime, int kheight, const float *in, int height, int hstride)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int in_stride;
|
||||||
|
in_stride = height+kheight-1;
|
||||||
|
for (i=0;i<out_channels;i++) {
|
||||||
|
int m;
|
||||||
|
RNN_CLEAR(&out[i*hstride], height);
|
||||||
|
for (m=0;m<in_channels;m++) {
|
||||||
|
int t;
|
||||||
|
for (t=0;t<ktime;t++) {
|
||||||
|
int h;
|
||||||
|
for (h=0;h<kheight;h++) {
|
||||||
|
int j;
|
||||||
|
for (j=0;j<height;j++) {
|
||||||
|
out[i*hstride + j] += weights[i*in_channels*ktime*kheight + m*ktime*kheight + t*kheight + h] *
|
||||||
|
in[t*in_channels*in_stride + m*in_stride + j + h];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* There's no intrinsics in this function (or the one above) because the gcc (and hopefully other compiler) auto-vectorizer is smart enough to
|
||||||
|
produce the right code by itself based on the compile flags. */
|
||||||
|
static void conv2d_3x3_float(float *out, const float *weights, int in_channels, int out_channels, const float *in, int height, int hstride)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int in_stride;
|
||||||
|
int kheight, ktime;
|
||||||
|
kheight = ktime = 3;
|
||||||
|
in_stride = height+kheight-1;
|
||||||
|
for (i=0;i<out_channels;i++) {
|
||||||
|
int m;
|
||||||
|
RNN_CLEAR(&out[i*hstride], height);
|
||||||
|
for (m=0;m<in_channels;m++) {
|
||||||
|
int j;
|
||||||
|
for (j=0;j<height;j++) {
|
||||||
|
/* Unrolled version of previous function -- compiler will figure out the indexing simplifications. */
|
||||||
|
out[i*hstride + j] += weights[i*in_channels*ktime*kheight + m*ktime*kheight + 0*kheight + 0]*in[0*in_channels*in_stride + m*in_stride + j + 0]
|
||||||
|
+ weights[i*in_channels*ktime*kheight + m*ktime*kheight + 0*kheight + 1]*in[0*in_channels*in_stride + m*in_stride + j + 1]
|
||||||
|
+ weights[i*in_channels*ktime*kheight + m*ktime*kheight + 0*kheight + 2]*in[0*in_channels*in_stride + m*in_stride + j + 2]
|
||||||
|
+ weights[i*in_channels*ktime*kheight + m*ktime*kheight + 1*kheight + 0]*in[1*in_channels*in_stride + m*in_stride + j + 0]
|
||||||
|
+ weights[i*in_channels*ktime*kheight + m*ktime*kheight + 1*kheight + 1]*in[1*in_channels*in_stride + m*in_stride + j + 1]
|
||||||
|
+ weights[i*in_channels*ktime*kheight + m*ktime*kheight + 1*kheight + 2]*in[1*in_channels*in_stride + m*in_stride + j + 2]
|
||||||
|
+ weights[i*in_channels*ktime*kheight + m*ktime*kheight + 2*kheight + 0]*in[2*in_channels*in_stride + m*in_stride + j + 0]
|
||||||
|
+ weights[i*in_channels*ktime*kheight + m*ktime*kheight + 2*kheight + 1]*in[2*in_channels*in_stride + m*in_stride + j + 1]
|
||||||
|
+ weights[i*in_channels*ktime*kheight + m*ktime*kheight + 2*kheight + 2]*in[2*in_channels*in_stride + m*in_stride + j + 2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAX_CONV2D_INPUTS 8192
|
||||||
|
|
||||||
|
void RTCD_SUF(compute_conv2d_)(const Conv2dLayer *conv, float *out, float *mem, const float *in, int height, int hstride, int activation)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
const float *bias;
|
||||||
|
float in_buf[MAX_CONV2D_INPUTS];
|
||||||
|
int time_stride;
|
||||||
|
celt_assert(in != out);
|
||||||
|
time_stride = conv->in_channels*(height+conv->kheight-1);
|
||||||
|
celt_assert(conv->ktime*time_stride <= MAX_CONV2D_INPUTS);
|
||||||
|
RNN_COPY(in_buf, mem, (conv->ktime-1)*time_stride);
|
||||||
|
RNN_COPY(&in_buf[(conv->ktime-1)*time_stride], in, time_stride);
|
||||||
|
RNN_COPY(mem, &in_buf[time_stride], (conv->ktime-1)*time_stride);
|
||||||
|
bias = conv->bias;
|
||||||
|
if (conv->kheight == 3 && conv->ktime == 3)
|
||||||
|
conv2d_3x3_float(out, conv->float_weights, conv->in_channels, conv->out_channels, in_buf, height, hstride);
|
||||||
|
else
|
||||||
|
conv2d_float(out, conv->float_weights, conv->in_channels, conv->out_channels, conv->ktime, conv->kheight, in_buf, height, hstride);
|
||||||
|
if (bias != NULL) {
|
||||||
|
for (i=0;i<conv->out_channels;i++) {
|
||||||
|
int j;
|
||||||
|
for (j=0;j<height;j++) out[i*hstride+j] += bias[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i=0;i<conv->out_channels;i++) {
|
||||||
|
RTCD_SUF(compute_activation_)(&out[i*hstride], &out[i*hstride], height, activation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef GCC_POP_OPTIONS
|
||||||
|
#pragma GCC pop_options
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
35
third_party/rnnoise/src/nnet_default.c
vendored
Normal file
35
third_party/rnnoise/src/nnet_default.c
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/* Copyright (c) 2018-2019 Mozilla
|
||||||
|
2023 Amazon */
|
||||||
|
/*
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
- Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||||||
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define RTCD_ARCH c
|
||||||
|
|
||||||
|
#include "nnet_arch.h"
|
||||||
159
third_party/rnnoise/src/opus_types.h
vendored
Normal file
159
third_party/rnnoise/src/opus_types.h
vendored
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
/* (C) COPYRIGHT 1994-2002 Xiph.Org Foundation */
|
||||||
|
/* Modified by Jean-Marc Valin */
|
||||||
|
/*
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
- Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||||
|
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
/* opus_types.h based on ogg_types.h from libogg */
|
||||||
|
|
||||||
|
/**
|
||||||
|
@file opus_types.h
|
||||||
|
@brief Opus reference implementation types
|
||||||
|
*/
|
||||||
|
#ifndef OPUS_TYPES_H
|
||||||
|
#define OPUS_TYPES_H
|
||||||
|
|
||||||
|
/* Use the real stdint.h if it's there (taken from Paul Hsieh's pstdint.h) */
|
||||||
|
#if (defined(__STDC__) && __STDC__ && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_)) || defined (HAVE_STDINT_H))
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef int16_t opus_int16;
|
||||||
|
typedef uint16_t opus_uint16;
|
||||||
|
typedef int32_t opus_int32;
|
||||||
|
typedef uint32_t opus_uint32;
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
|
||||||
|
# if defined(__CYGWIN__)
|
||||||
|
# include <_G_config.h>
|
||||||
|
typedef _G_int32_t opus_int32;
|
||||||
|
typedef _G_uint32_t opus_uint32;
|
||||||
|
typedef _G_int16 opus_int16;
|
||||||
|
typedef _G_uint16 opus_uint16;
|
||||||
|
# elif defined(__MINGW32__)
|
||||||
|
typedef short opus_int16;
|
||||||
|
typedef unsigned short opus_uint16;
|
||||||
|
typedef int opus_int32;
|
||||||
|
typedef unsigned int opus_uint32;
|
||||||
|
# elif defined(__MWERKS__)
|
||||||
|
typedef int opus_int32;
|
||||||
|
typedef unsigned int opus_uint32;
|
||||||
|
typedef short opus_int16;
|
||||||
|
typedef unsigned short opus_uint16;
|
||||||
|
# else
|
||||||
|
/* MSVC/Borland */
|
||||||
|
typedef __int32 opus_int32;
|
||||||
|
typedef unsigned __int32 opus_uint32;
|
||||||
|
typedef __int16 opus_int16;
|
||||||
|
typedef unsigned __int16 opus_uint16;
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(__MACOS__)
|
||||||
|
|
||||||
|
# include <sys/types.h>
|
||||||
|
typedef SInt16 opus_int16;
|
||||||
|
typedef UInt16 opus_uint16;
|
||||||
|
typedef SInt32 opus_int32;
|
||||||
|
typedef UInt32 opus_uint32;
|
||||||
|
|
||||||
|
#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */
|
||||||
|
|
||||||
|
# include <sys/types.h>
|
||||||
|
typedef int16_t opus_int16;
|
||||||
|
typedef u_int16_t opus_uint16;
|
||||||
|
typedef int32_t opus_int32;
|
||||||
|
typedef u_int32_t opus_uint32;
|
||||||
|
|
||||||
|
#elif defined(__BEOS__)
|
||||||
|
|
||||||
|
/* Be */
|
||||||
|
# include <inttypes.h>
|
||||||
|
typedef int16 opus_int16;
|
||||||
|
typedef u_int16 opus_uint16;
|
||||||
|
typedef int32_t opus_int32;
|
||||||
|
typedef u_int32_t opus_uint32;
|
||||||
|
|
||||||
|
#elif defined (__EMX__)
|
||||||
|
|
||||||
|
/* OS/2 GCC */
|
||||||
|
typedef short opus_int16;
|
||||||
|
typedef unsigned short opus_uint16;
|
||||||
|
typedef int opus_int32;
|
||||||
|
typedef unsigned int opus_uint32;
|
||||||
|
|
||||||
|
#elif defined (DJGPP)
|
||||||
|
|
||||||
|
/* DJGPP */
|
||||||
|
typedef short opus_int16;
|
||||||
|
typedef unsigned short opus_uint16;
|
||||||
|
typedef int opus_int32;
|
||||||
|
typedef unsigned int opus_uint32;
|
||||||
|
|
||||||
|
#elif defined(R5900)
|
||||||
|
|
||||||
|
/* PS2 EE */
|
||||||
|
typedef int opus_int32;
|
||||||
|
typedef unsigned opus_uint32;
|
||||||
|
typedef short opus_int16;
|
||||||
|
typedef unsigned short opus_uint16;
|
||||||
|
|
||||||
|
#elif defined(__SYMBIAN32__)
|
||||||
|
|
||||||
|
/* Symbian GCC */
|
||||||
|
typedef signed short opus_int16;
|
||||||
|
typedef unsigned short opus_uint16;
|
||||||
|
typedef signed int opus_int32;
|
||||||
|
typedef unsigned int opus_uint32;
|
||||||
|
|
||||||
|
#elif defined(CONFIG_TI_C54X) || defined (CONFIG_TI_C55X)
|
||||||
|
|
||||||
|
typedef short opus_int16;
|
||||||
|
typedef unsigned short opus_uint16;
|
||||||
|
typedef long opus_int32;
|
||||||
|
typedef unsigned long opus_uint32;
|
||||||
|
|
||||||
|
#elif defined(CONFIG_TI_C6X)
|
||||||
|
|
||||||
|
typedef short opus_int16;
|
||||||
|
typedef unsigned short opus_uint16;
|
||||||
|
typedef int opus_int32;
|
||||||
|
typedef unsigned int opus_uint32;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* Give up, take a reasonable guess */
|
||||||
|
typedef short opus_int16;
|
||||||
|
typedef unsigned short opus_uint16;
|
||||||
|
typedef int opus_int32;
|
||||||
|
typedef unsigned int opus_uint32;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define opus_int int /* used for counters etc; at least 16 bits */
|
||||||
|
#define opus_int64 long long
|
||||||
|
#define opus_int8 signed char
|
||||||
|
|
||||||
|
#define opus_uint unsigned int /* used for counters etc; at least 16 bits */
|
||||||
|
#define opus_uint64 unsigned long long
|
||||||
|
#define opus_uint8 unsigned char
|
||||||
|
|
||||||
|
#endif /* OPUS_TYPES_H */
|
||||||
237
third_party/rnnoise/src/parse_lpcnet_weights.c
vendored
Normal file
237
third_party/rnnoise/src/parse_lpcnet_weights.c
vendored
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
/* Copyright (c) 2023 Amazon */
|
||||||
|
/*
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
- Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||||||
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "nnet.h"
|
||||||
|
|
||||||
|
#define SPARSE_BLOCK_SIZE 32
|
||||||
|
|
||||||
|
static int parse_record(const void **data, int *len, WeightArray *array) {
|
||||||
|
WeightHead *h = (WeightHead *)*data;
|
||||||
|
if (*len < WEIGHT_BLOCK_SIZE) return -1;
|
||||||
|
if (h->block_size < h->size) return -1;
|
||||||
|
if (h->block_size > *len-WEIGHT_BLOCK_SIZE) return -1;
|
||||||
|
if (h->name[sizeof(h->name)-1] != 0) return -1;
|
||||||
|
if (h->size < 0) return -1;
|
||||||
|
array->name = h->name;
|
||||||
|
array->type = h->type;
|
||||||
|
array->size = h->size;
|
||||||
|
array->data = (void*)((unsigned char*)(*data)+WEIGHT_BLOCK_SIZE);
|
||||||
|
|
||||||
|
*data = (void*)((unsigned char*)*data + h->block_size+WEIGHT_BLOCK_SIZE);
|
||||||
|
*len -= h->block_size+WEIGHT_BLOCK_SIZE;
|
||||||
|
return array->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parse_weights(WeightArray **list, const void *data, int len)
|
||||||
|
{
|
||||||
|
int nb_arrays=0;
|
||||||
|
int capacity=20;
|
||||||
|
*list = calloc(capacity*sizeof(WeightArray), 1);
|
||||||
|
while (len > 0) {
|
||||||
|
int ret;
|
||||||
|
WeightArray array = {NULL, 0, 0, 0};
|
||||||
|
ret = parse_record(&data, &len, &array);
|
||||||
|
if (ret > 0) {
|
||||||
|
if (nb_arrays+1 >= capacity) {
|
||||||
|
/* Make sure there's room for the ending NULL element too. */
|
||||||
|
capacity = capacity*3/2;
|
||||||
|
*list = realloc(*list, capacity*sizeof(WeightArray));
|
||||||
|
}
|
||||||
|
(*list)[nb_arrays++] = array;
|
||||||
|
} else {
|
||||||
|
free(*list);
|
||||||
|
*list = NULL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(*list)[nb_arrays].name=NULL;
|
||||||
|
return nb_arrays;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const void *find_array_entry(const WeightArray *arrays, const char *name) {
|
||||||
|
while (arrays->name && strcmp(arrays->name, name) != 0) arrays++;
|
||||||
|
return arrays;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const void *find_array_check(const WeightArray *arrays, const char *name, int size) {
|
||||||
|
const WeightArray *a = find_array_entry(arrays, name);
|
||||||
|
if (a->name && a->size == size) return a->data;
|
||||||
|
else return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const void *opt_array_check(const WeightArray *arrays, const char *name, int size, int *error) {
|
||||||
|
const WeightArray *a = find_array_entry(arrays, name);
|
||||||
|
*error = (a->name != NULL && a->size != size);
|
||||||
|
if (a->name && a->size == size) return a->data;
|
||||||
|
else return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const void *find_idx_check(const WeightArray *arrays, const char *name, int nb_in, int nb_out, int *total_blocks) {
|
||||||
|
int remain;
|
||||||
|
const int *idx;
|
||||||
|
const WeightArray *a = find_array_entry(arrays, name);
|
||||||
|
*total_blocks = 0;
|
||||||
|
if (a == NULL) return NULL;
|
||||||
|
idx = a->data;
|
||||||
|
remain = a->size/sizeof(int);
|
||||||
|
while (remain > 0) {
|
||||||
|
int nb_blocks;
|
||||||
|
int i;
|
||||||
|
nb_blocks = *idx++;
|
||||||
|
if (remain < nb_blocks+1) return NULL;
|
||||||
|
for (i=0;i<nb_blocks;i++) {
|
||||||
|
int pos = *idx++;
|
||||||
|
if (pos+3 >= nb_in || (pos&0x3)) return NULL;
|
||||||
|
}
|
||||||
|
nb_out -= 8;
|
||||||
|
remain -= nb_blocks+1;
|
||||||
|
*total_blocks += nb_blocks;
|
||||||
|
}
|
||||||
|
if (nb_out != 0) return NULL;
|
||||||
|
return a->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
int linear_init(LinearLayer *layer, const WeightArray *arrays,
|
||||||
|
const char *bias,
|
||||||
|
const char *subias,
|
||||||
|
const char *weights,
|
||||||
|
const char *float_weights,
|
||||||
|
const char *weights_idx,
|
||||||
|
const char *diag,
|
||||||
|
const char *scale,
|
||||||
|
int nb_inputs,
|
||||||
|
int nb_outputs)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
layer->bias = NULL;
|
||||||
|
layer->subias = NULL;
|
||||||
|
layer->weights = NULL;
|
||||||
|
layer->float_weights = NULL;
|
||||||
|
layer->weights_idx = NULL;
|
||||||
|
layer->diag = NULL;
|
||||||
|
layer->scale = NULL;
|
||||||
|
if (bias != NULL) {
|
||||||
|
if ((layer->bias = find_array_check(arrays, bias, nb_outputs*sizeof(layer->bias[0]))) == NULL) return 1;
|
||||||
|
}
|
||||||
|
if (subias != NULL) {
|
||||||
|
if ((layer->subias = find_array_check(arrays, subias, nb_outputs*sizeof(layer->subias[0]))) == NULL) return 1;
|
||||||
|
}
|
||||||
|
if (weights_idx != NULL) {
|
||||||
|
int total_blocks;
|
||||||
|
if ((layer->weights_idx = find_idx_check(arrays, weights_idx, nb_inputs, nb_outputs, &total_blocks)) == NULL) return 1;
|
||||||
|
if (weights != NULL) {
|
||||||
|
if ((layer->weights = find_array_check(arrays, weights, SPARSE_BLOCK_SIZE*total_blocks*sizeof(layer->weights[0]))) == NULL) return 1;
|
||||||
|
}
|
||||||
|
if (float_weights != NULL) {
|
||||||
|
layer->float_weights = opt_array_check(arrays, float_weights, SPARSE_BLOCK_SIZE*total_blocks*sizeof(layer->float_weights[0]), &err);
|
||||||
|
if (err) return 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (weights != NULL) {
|
||||||
|
if ((layer->weights = find_array_check(arrays, weights, nb_inputs*nb_outputs*sizeof(layer->weights[0]))) == NULL) return 1;
|
||||||
|
}
|
||||||
|
if (float_weights != NULL) {
|
||||||
|
layer->float_weights = opt_array_check(arrays, float_weights, nb_inputs*nb_outputs*sizeof(layer->float_weights[0]), &err);
|
||||||
|
if (err) return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (diag != NULL) {
|
||||||
|
if ((layer->diag = find_array_check(arrays, diag, nb_outputs*sizeof(layer->diag[0]))) == NULL) return 1;
|
||||||
|
}
|
||||||
|
if (weights != NULL) {
|
||||||
|
if ((layer->scale = find_array_check(arrays, scale, nb_outputs*sizeof(layer->scale[0]))) == NULL) return 1;
|
||||||
|
}
|
||||||
|
layer->nb_inputs = nb_inputs;
|
||||||
|
layer->nb_outputs = nb_outputs;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int conv2d_init(Conv2dLayer *layer, const WeightArray *arrays,
|
||||||
|
const char *bias,
|
||||||
|
const char *float_weights,
|
||||||
|
int in_channels,
|
||||||
|
int out_channels,
|
||||||
|
int ktime,
|
||||||
|
int kheight)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
layer->bias = NULL;
|
||||||
|
layer->float_weights = NULL;
|
||||||
|
if (bias != NULL) {
|
||||||
|
if ((layer->bias = find_array_check(arrays, bias, out_channels*sizeof(layer->bias[0]))) == NULL) return 1;
|
||||||
|
}
|
||||||
|
if (float_weights != NULL) {
|
||||||
|
layer->float_weights = opt_array_check(arrays, float_weights, in_channels*out_channels*ktime*kheight*sizeof(layer->float_weights[0]), &err);
|
||||||
|
if (err) return 1;
|
||||||
|
}
|
||||||
|
layer->in_channels = in_channels;
|
||||||
|
layer->out_channels = out_channels;
|
||||||
|
layer->ktime = ktime;
|
||||||
|
layer->kheight = kheight;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
void *data;
|
||||||
|
int len;
|
||||||
|
int nb_arrays;
|
||||||
|
int i;
|
||||||
|
WeightArray *list;
|
||||||
|
struct stat st;
|
||||||
|
const char *filename = "weights_blob.bin";
|
||||||
|
stat(filename, &st);
|
||||||
|
len = st.st_size;
|
||||||
|
fd = open(filename, O_RDONLY);
|
||||||
|
data = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);
|
||||||
|
printf("size is %d\n", len);
|
||||||
|
nb_arrays = parse_weights(&list, data, len);
|
||||||
|
for (i=0;i<nb_arrays;i++) {
|
||||||
|
printf("found %s: size %d\n", list[i].name, list[i].size);
|
||||||
|
}
|
||||||
|
printf("%p\n", list[i].name);
|
||||||
|
free(list);
|
||||||
|
munmap(data, len);
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
528
third_party/rnnoise/src/pitch.c
vendored
Normal file
528
third_party/rnnoise/src/pitch.c
vendored
Normal file
@@ -0,0 +1,528 @@
|
|||||||
|
/* Copyright (c) 2007-2008 CSIRO
|
||||||
|
Copyright (c) 2007-2009 Xiph.Org Foundation
|
||||||
|
Written by Jean-Marc Valin */
|
||||||
|
/**
|
||||||
|
@file pitch.c
|
||||||
|
@brief Pitch analysis
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
- Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||||
|
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "pitch.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "denoise.h"
|
||||||
|
#include "celt_lpc.h"
|
||||||
|
#include "math.h"
|
||||||
|
|
||||||
|
static void find_best_pitch(opus_val32 *xcorr, opus_val16 *y, int len,
|
||||||
|
int max_pitch, int *best_pitch
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
, int yshift, opus_val32 maxcorr
|
||||||
|
#endif
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
opus_val32 Syy=1;
|
||||||
|
opus_val16 best_num[2];
|
||||||
|
opus_val32 best_den[2];
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
int xshift;
|
||||||
|
|
||||||
|
xshift = celt_ilog2(maxcorr)-14;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
best_num[0] = -1;
|
||||||
|
best_num[1] = -1;
|
||||||
|
best_den[0] = 0;
|
||||||
|
best_den[1] = 0;
|
||||||
|
best_pitch[0] = 0;
|
||||||
|
best_pitch[1] = 1;
|
||||||
|
for (j=0;j<len;j++)
|
||||||
|
Syy = ADD32(Syy, SHR32(MULT16_16(y[j],y[j]), yshift));
|
||||||
|
for (i=0;i<max_pitch;i++)
|
||||||
|
{
|
||||||
|
if (xcorr[i]>0)
|
||||||
|
{
|
||||||
|
opus_val16 num;
|
||||||
|
opus_val32 xcorr16;
|
||||||
|
xcorr16 = EXTRACT16(VSHR32(xcorr[i], xshift));
|
||||||
|
#ifndef FIXED_POINT
|
||||||
|
/* Considering the range of xcorr16, this should avoid both underflows
|
||||||
|
and overflows (inf) when squaring xcorr16 */
|
||||||
|
xcorr16 *= 1e-12f;
|
||||||
|
#endif
|
||||||
|
num = MULT16_16_Q15(xcorr16,xcorr16);
|
||||||
|
if (MULT16_32_Q15(num,best_den[1]) > MULT16_32_Q15(best_num[1],Syy))
|
||||||
|
{
|
||||||
|
if (MULT16_32_Q15(num,best_den[0]) > MULT16_32_Q15(best_num[0],Syy))
|
||||||
|
{
|
||||||
|
best_num[1] = best_num[0];
|
||||||
|
best_den[1] = best_den[0];
|
||||||
|
best_pitch[1] = best_pitch[0];
|
||||||
|
best_num[0] = num;
|
||||||
|
best_den[0] = Syy;
|
||||||
|
best_pitch[0] = i;
|
||||||
|
} else {
|
||||||
|
best_num[1] = num;
|
||||||
|
best_den[1] = Syy;
|
||||||
|
best_pitch[1] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Syy += SHR32(MULT16_16(y[i+len],y[i+len]),yshift) - SHR32(MULT16_16(y[i],y[i]),yshift);
|
||||||
|
Syy = MAX32(1, Syy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void celt_fir5(const opus_val16 *x,
|
||||||
|
const opus_val16 *num,
|
||||||
|
opus_val16 *y,
|
||||||
|
int N,
|
||||||
|
opus_val16 *mem)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
opus_val16 num0, num1, num2, num3, num4;
|
||||||
|
opus_val32 mem0, mem1, mem2, mem3, mem4;
|
||||||
|
num0=num[0];
|
||||||
|
num1=num[1];
|
||||||
|
num2=num[2];
|
||||||
|
num3=num[3];
|
||||||
|
num4=num[4];
|
||||||
|
mem0=mem[0];
|
||||||
|
mem1=mem[1];
|
||||||
|
mem2=mem[2];
|
||||||
|
mem3=mem[3];
|
||||||
|
mem4=mem[4];
|
||||||
|
for (i=0;i<N;i++)
|
||||||
|
{
|
||||||
|
opus_val32 sum = SHL32(EXTEND32(x[i]), SIG_SHIFT);
|
||||||
|
sum = MAC16_16(sum,num0,mem0);
|
||||||
|
sum = MAC16_16(sum,num1,mem1);
|
||||||
|
sum = MAC16_16(sum,num2,mem2);
|
||||||
|
sum = MAC16_16(sum,num3,mem3);
|
||||||
|
sum = MAC16_16(sum,num4,mem4);
|
||||||
|
mem4 = mem3;
|
||||||
|
mem3 = mem2;
|
||||||
|
mem2 = mem1;
|
||||||
|
mem1 = mem0;
|
||||||
|
mem0 = x[i];
|
||||||
|
y[i] = ROUND16(sum, SIG_SHIFT);
|
||||||
|
}
|
||||||
|
mem[0]=mem0;
|
||||||
|
mem[1]=mem1;
|
||||||
|
mem[2]=mem2;
|
||||||
|
mem[3]=mem3;
|
||||||
|
mem[4]=mem4;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void rnn_pitch_downsample(celt_sig *x[], opus_val16 *x_lp,
|
||||||
|
int len, int C)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
opus_val32 ac[5];
|
||||||
|
opus_val16 tmp=Q15ONE;
|
||||||
|
opus_val16 lpc[4], mem[5]={0,0,0,0,0};
|
||||||
|
opus_val16 lpc2[5];
|
||||||
|
opus_val16 c1 = QCONST16(.8f,15);
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
int shift;
|
||||||
|
opus_val32 maxabs = celt_maxabs32(x[0], len);
|
||||||
|
if (C==2)
|
||||||
|
{
|
||||||
|
opus_val32 maxabs_1 = celt_maxabs32(x[1], len);
|
||||||
|
maxabs = MAX32(maxabs, maxabs_1);
|
||||||
|
}
|
||||||
|
if (maxabs<1)
|
||||||
|
maxabs=1;
|
||||||
|
shift = celt_ilog2(maxabs)-10;
|
||||||
|
if (shift<0)
|
||||||
|
shift=0;
|
||||||
|
if (C==2)
|
||||||
|
shift++;
|
||||||
|
#endif
|
||||||
|
for (i=1;i<len>>1;i++)
|
||||||
|
x_lp[i] = SHR32(HALF32(HALF32(x[0][(2*i-1)]+x[0][(2*i+1)])+x[0][2*i]), shift);
|
||||||
|
x_lp[0] = SHR32(HALF32(HALF32(x[0][1])+x[0][0]), shift);
|
||||||
|
if (C==2)
|
||||||
|
{
|
||||||
|
for (i=1;i<len>>1;i++)
|
||||||
|
x_lp[i] += SHR32(HALF32(HALF32(x[1][(2*i-1)]+x[1][(2*i+1)])+x[1][2*i]), shift);
|
||||||
|
x_lp[0] += SHR32(HALF32(HALF32(x[1][1])+x[1][0]), shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
rnn_autocorr(x_lp, ac, NULL, 0,
|
||||||
|
4, len>>1);
|
||||||
|
|
||||||
|
/* Noise floor -40 dB */
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
ac[0] += SHR32(ac[0],13);
|
||||||
|
#else
|
||||||
|
ac[0] *= 1.0001f;
|
||||||
|
#endif
|
||||||
|
/* Lag windowing */
|
||||||
|
for (i=1;i<=4;i++)
|
||||||
|
{
|
||||||
|
/*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
ac[i] -= MULT16_32_Q15(2*i*i, ac[i]);
|
||||||
|
#else
|
||||||
|
ac[i] -= ac[i]*(.008f*i)*(.008f*i);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
rnn_lpc(lpc, ac, 4);
|
||||||
|
for (i=0;i<4;i++)
|
||||||
|
{
|
||||||
|
tmp = MULT16_16_Q15(QCONST16(.9f,15), tmp);
|
||||||
|
lpc[i] = MULT16_16_Q15(lpc[i], tmp);
|
||||||
|
}
|
||||||
|
/* Add a zero */
|
||||||
|
lpc2[0] = lpc[0] + QCONST16(.8f,SIG_SHIFT);
|
||||||
|
lpc2[1] = lpc[1] + MULT16_16_Q15(c1,lpc[0]);
|
||||||
|
lpc2[2] = lpc[2] + MULT16_16_Q15(c1,lpc[1]);
|
||||||
|
lpc2[3] = lpc[3] + MULT16_16_Q15(c1,lpc[2]);
|
||||||
|
lpc2[4] = MULT16_16_Q15(c1,lpc[3]);
|
||||||
|
celt_fir5(x_lp, lpc2, x_lp, len>>1, mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rnn_pitch_xcorr(const opus_val16 *_x, const opus_val16 *_y,
|
||||||
|
opus_val32 *xcorr, int len, int max_pitch)
|
||||||
|
{
|
||||||
|
|
||||||
|
#if 0 /* This is a simple version of the pitch correlation that should work
|
||||||
|
well on DSPs like Blackfin and TI C5x/C6x */
|
||||||
|
int i, j;
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
opus_val32 maxcorr=1;
|
||||||
|
#endif
|
||||||
|
for (i=0;i<max_pitch;i++)
|
||||||
|
{
|
||||||
|
opus_val32 sum = 0;
|
||||||
|
for (j=0;j<len;j++)
|
||||||
|
sum = MAC16_16(sum, _x[j], _y[i+j]);
|
||||||
|
xcorr[i] = sum;
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
maxcorr = MAX32(maxcorr, sum);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
return maxcorr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else /* Unrolled version of the pitch correlation -- runs faster on x86 and ARM */
|
||||||
|
int i;
|
||||||
|
/*The EDSP version requires that max_pitch is at least 1, and that _x is
|
||||||
|
32-bit aligned.
|
||||||
|
Since it's hard to put asserts in assembly, put them here.*/
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
opus_val32 maxcorr=1;
|
||||||
|
#endif
|
||||||
|
celt_assert(max_pitch>0);
|
||||||
|
celt_assert((((unsigned char *)_x-(unsigned char *)NULL)&3)==0);
|
||||||
|
for (i=0;i<max_pitch-3;i+=4)
|
||||||
|
{
|
||||||
|
opus_val32 sum[4]={0,0,0,0};
|
||||||
|
xcorr_kernel(_x, _y+i, sum, len);
|
||||||
|
xcorr[i]=sum[0];
|
||||||
|
xcorr[i+1]=sum[1];
|
||||||
|
xcorr[i+2]=sum[2];
|
||||||
|
xcorr[i+3]=sum[3];
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
sum[0] = MAX32(sum[0], sum[1]);
|
||||||
|
sum[2] = MAX32(sum[2], sum[3]);
|
||||||
|
sum[0] = MAX32(sum[0], sum[2]);
|
||||||
|
maxcorr = MAX32(maxcorr, sum[0]);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
/* In case max_pitch isn't a multiple of 4, do non-unrolled version. */
|
||||||
|
for (;i<max_pitch;i++)
|
||||||
|
{
|
||||||
|
opus_val32 sum;
|
||||||
|
sum = celt_inner_prod(_x, _y+i, len);
|
||||||
|
xcorr[i] = sum;
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
maxcorr = MAX32(maxcorr, sum);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
return maxcorr;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void rnn_pitch_search(const opus_val16 *x_lp, opus_val16 *y,
|
||||||
|
int len, int max_pitch, int *pitch)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
int lag;
|
||||||
|
int best_pitch[2]={0,0};
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
opus_val32 maxcorr;
|
||||||
|
opus_val32 xmax, ymax;
|
||||||
|
int shift=0;
|
||||||
|
#endif
|
||||||
|
int offset;
|
||||||
|
opus_val16 x_lp4[PITCH_FRAME_SIZE>>2];
|
||||||
|
opus_val16 y_lp4[(PITCH_FRAME_SIZE+PITCH_MAX_PERIOD)>>2];
|
||||||
|
opus_val32 xcorr[PITCH_MAX_PERIOD>>1];
|
||||||
|
|
||||||
|
celt_assert(len <= PITCH_FRAME_SIZE);
|
||||||
|
celt_assert(max_pitch <= PITCH_MAX_PERIOD);
|
||||||
|
celt_assert(len>0);
|
||||||
|
celt_assert(max_pitch>0);
|
||||||
|
lag = len+max_pitch;
|
||||||
|
|
||||||
|
|
||||||
|
/* Downsample by 2 again */
|
||||||
|
for (j=0;j<len>>2;j++)
|
||||||
|
x_lp4[j] = x_lp[2*j];
|
||||||
|
for (j=0;j<lag>>2;j++)
|
||||||
|
y_lp4[j] = y[2*j];
|
||||||
|
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
xmax = celt_maxabs16(x_lp4, len>>2);
|
||||||
|
ymax = celt_maxabs16(y_lp4, lag>>2);
|
||||||
|
shift = celt_ilog2(MAX32(1, MAX32(xmax, ymax)))-11;
|
||||||
|
if (shift>0)
|
||||||
|
{
|
||||||
|
for (j=0;j<len>>2;j++)
|
||||||
|
x_lp4[j] = SHR16(x_lp4[j], shift);
|
||||||
|
for (j=0;j<lag>>2;j++)
|
||||||
|
y_lp4[j] = SHR16(y_lp4[j], shift);
|
||||||
|
/* Use double the shift for a MAC */
|
||||||
|
shift *= 2;
|
||||||
|
} else {
|
||||||
|
shift = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Coarse search with 4x decimation */
|
||||||
|
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
maxcorr =
|
||||||
|
#endif
|
||||||
|
rnn_pitch_xcorr(x_lp4, y_lp4, xcorr, len>>2, max_pitch>>2);
|
||||||
|
|
||||||
|
find_best_pitch(xcorr, y_lp4, len>>2, max_pitch>>2, best_pitch
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
, 0, maxcorr
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Finer search with 2x decimation */
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
maxcorr=1;
|
||||||
|
#endif
|
||||||
|
for (i=0;i<max_pitch>>1;i++)
|
||||||
|
{
|
||||||
|
opus_val32 sum;
|
||||||
|
xcorr[i] = 0;
|
||||||
|
if (abs(i-2*best_pitch[0])>2 && abs(i-2*best_pitch[1])>2)
|
||||||
|
continue;
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
sum = 0;
|
||||||
|
for (j=0;j<len>>1;j++)
|
||||||
|
sum += SHR32(MULT16_16(x_lp[j],y[i+j]), shift);
|
||||||
|
#else
|
||||||
|
sum = celt_inner_prod(x_lp, y+i, len>>1);
|
||||||
|
#endif
|
||||||
|
xcorr[i] = MAX32(-1, sum);
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
maxcorr = MAX32(maxcorr, sum);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
find_best_pitch(xcorr, y, len>>1, max_pitch>>1, best_pitch
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
, shift+1, maxcorr
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Refine by pseudo-interpolation */
|
||||||
|
if (best_pitch[0]>0 && best_pitch[0]<(max_pitch>>1)-1)
|
||||||
|
{
|
||||||
|
opus_val32 a, b, c;
|
||||||
|
a = xcorr[best_pitch[0]-1];
|
||||||
|
b = xcorr[best_pitch[0]];
|
||||||
|
c = xcorr[best_pitch[0]+1];
|
||||||
|
if ((c-a) > MULT16_32_Q15(QCONST16(.7f,15),b-a))
|
||||||
|
offset = 1;
|
||||||
|
else if ((a-c) > MULT16_32_Q15(QCONST16(.7f,15),b-c))
|
||||||
|
offset = -1;
|
||||||
|
else
|
||||||
|
offset = 0;
|
||||||
|
} else {
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
*pitch = 2*best_pitch[0]-offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
static opus_val16 compute_pitch_gain(opus_val32 xy, opus_val32 xx, opus_val32 yy)
|
||||||
|
{
|
||||||
|
opus_val32 x2y2;
|
||||||
|
int sx, sy, shift;
|
||||||
|
opus_val32 g;
|
||||||
|
opus_val16 den;
|
||||||
|
if (xy == 0 || xx == 0 || yy == 0)
|
||||||
|
return 0;
|
||||||
|
sx = celt_ilog2(xx)-14;
|
||||||
|
sy = celt_ilog2(yy)-14;
|
||||||
|
shift = sx + sy;
|
||||||
|
x2y2 = SHR32(MULT16_16(VSHR32(xx, sx), VSHR32(yy, sy)), 14);
|
||||||
|
if (shift & 1) {
|
||||||
|
if (x2y2 < 32768)
|
||||||
|
{
|
||||||
|
x2y2 <<= 1;
|
||||||
|
shift--;
|
||||||
|
} else {
|
||||||
|
x2y2 >>= 1;
|
||||||
|
shift++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
den = celt_rsqrt_norm(x2y2);
|
||||||
|
g = MULT16_32_Q15(den, xy);
|
||||||
|
g = VSHR32(g, (shift>>1)-1);
|
||||||
|
return EXTRACT16(MIN32(g, Q15ONE));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static opus_val16 compute_pitch_gain(opus_val32 xy, opus_val32 xx, opus_val32 yy)
|
||||||
|
{
|
||||||
|
return xy/sqrt(1+xx*yy);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const int second_check[16] = {0, 0, 3, 2, 3, 2, 5, 2, 3, 2, 3, 2, 5, 2, 3, 2};
|
||||||
|
opus_val16 rnn_remove_doubling(opus_val16 *x, int maxperiod, int minperiod,
|
||||||
|
int N, int *T0_, int prev_period, opus_val16 prev_gain)
|
||||||
|
{
|
||||||
|
int k, i, T, T0;
|
||||||
|
opus_val16 g, g0;
|
||||||
|
opus_val16 pg;
|
||||||
|
opus_val32 xy,xx,yy,xy2;
|
||||||
|
opus_val32 xcorr[3];
|
||||||
|
opus_val32 best_xy, best_yy;
|
||||||
|
int offset;
|
||||||
|
int minperiod0;
|
||||||
|
opus_val32 yy_lookup[PITCH_MAX_PERIOD+1];
|
||||||
|
|
||||||
|
celt_assert(maxperiod <= PITCH_MAX_PERIOD);
|
||||||
|
|
||||||
|
minperiod0 = minperiod;
|
||||||
|
maxperiod /= 2;
|
||||||
|
minperiod /= 2;
|
||||||
|
*T0_ /= 2;
|
||||||
|
prev_period /= 2;
|
||||||
|
N /= 2;
|
||||||
|
x += maxperiod;
|
||||||
|
if (*T0_>=maxperiod)
|
||||||
|
*T0_=maxperiod-1;
|
||||||
|
|
||||||
|
T = T0 = *T0_;
|
||||||
|
dual_inner_prod(x, x, x-T0, N, &xx, &xy);
|
||||||
|
yy_lookup[0] = xx;
|
||||||
|
yy=xx;
|
||||||
|
for (i=1;i<=maxperiod;i++)
|
||||||
|
{
|
||||||
|
yy = yy+MULT16_16(x[-i],x[-i])-MULT16_16(x[N-i],x[N-i]);
|
||||||
|
yy_lookup[i] = MAX32(0, yy);
|
||||||
|
}
|
||||||
|
yy = yy_lookup[T0];
|
||||||
|
best_xy = xy;
|
||||||
|
best_yy = yy;
|
||||||
|
g = g0 = compute_pitch_gain(xy, xx, yy);
|
||||||
|
/* Look for any pitch at T/k */
|
||||||
|
for (k=2;k<=15;k++)
|
||||||
|
{
|
||||||
|
int T1, T1b;
|
||||||
|
opus_val16 g1;
|
||||||
|
opus_val16 cont=0;
|
||||||
|
opus_val16 thresh;
|
||||||
|
T1 = (2*T0+k)/(2*k);
|
||||||
|
if (T1 < minperiod)
|
||||||
|
break;
|
||||||
|
/* Look for another strong correlation at T1b */
|
||||||
|
if (k==2)
|
||||||
|
{
|
||||||
|
if (T1+T0>maxperiod)
|
||||||
|
T1b = T0;
|
||||||
|
else
|
||||||
|
T1b = T0+T1;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
T1b = (2*second_check[k]*T0+k)/(2*k);
|
||||||
|
}
|
||||||
|
dual_inner_prod(x, &x[-T1], &x[-T1b], N, &xy, &xy2);
|
||||||
|
xy = HALF32(xy + xy2);
|
||||||
|
yy = HALF32(yy_lookup[T1] + yy_lookup[T1b]);
|
||||||
|
g1 = compute_pitch_gain(xy, xx, yy);
|
||||||
|
if (abs(T1-prev_period)<=1)
|
||||||
|
cont = prev_gain;
|
||||||
|
else if (abs(T1-prev_period)<=2 && 5*k*k < T0)
|
||||||
|
cont = HALF16(prev_gain);
|
||||||
|
else
|
||||||
|
cont = 0;
|
||||||
|
thresh = MAX16(QCONST16(.3f,15), MULT16_16_Q15(QCONST16(.7f,15),g0)-cont);
|
||||||
|
/* Bias against very high pitch (very short period) to avoid false-positives
|
||||||
|
due to short-term correlation */
|
||||||
|
if (T1<3*minperiod)
|
||||||
|
thresh = MAX16(QCONST16(.4f,15), MULT16_16_Q15(QCONST16(.85f,15),g0)-cont);
|
||||||
|
else if (T1<2*minperiod)
|
||||||
|
thresh = MAX16(QCONST16(.5f,15), MULT16_16_Q15(QCONST16(.9f,15),g0)-cont);
|
||||||
|
if (g1 > thresh)
|
||||||
|
{
|
||||||
|
best_xy = xy;
|
||||||
|
best_yy = yy;
|
||||||
|
T = T1;
|
||||||
|
g = g1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
best_xy = MAX32(0, best_xy);
|
||||||
|
if (best_yy <= best_xy)
|
||||||
|
pg = Q15ONE;
|
||||||
|
else
|
||||||
|
pg = best_xy/(best_yy+1);
|
||||||
|
|
||||||
|
for (k=0;k<3;k++)
|
||||||
|
xcorr[k] = celt_inner_prod(x, x-(T+k-1), N);
|
||||||
|
if ((xcorr[2]-xcorr[0]) > MULT16_32_Q15(QCONST16(.7f,15),xcorr[1]-xcorr[0]))
|
||||||
|
offset = 1;
|
||||||
|
else if ((xcorr[0]-xcorr[2]) > MULT16_32_Q15(QCONST16(.7f,15),xcorr[1]-xcorr[2]))
|
||||||
|
offset = -1;
|
||||||
|
else
|
||||||
|
offset = 0;
|
||||||
|
if (pg > g)
|
||||||
|
pg = g;
|
||||||
|
*T0_ = 2*T+offset;
|
||||||
|
|
||||||
|
if (*T0_<minperiod0)
|
||||||
|
*T0_=minperiod0;
|
||||||
|
return pg;
|
||||||
|
}
|
||||||
147
third_party/rnnoise/src/pitch.h
vendored
Normal file
147
third_party/rnnoise/src/pitch.h
vendored
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
/* Copyright (c) 2007-2008 CSIRO
|
||||||
|
Copyright (c) 2007-2009 Xiph.Org Foundation
|
||||||
|
Written by Jean-Marc Valin */
|
||||||
|
/**
|
||||||
|
@file pitch.h
|
||||||
|
@brief Pitch analysis
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
- Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||||
|
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PITCH_H
|
||||||
|
#define PITCH_H
|
||||||
|
|
||||||
|
#include "arch.h"
|
||||||
|
|
||||||
|
void rnn_pitch_downsample(celt_sig *x[], opus_val16 *x_lp,
|
||||||
|
int len, int C);
|
||||||
|
|
||||||
|
void rnn_pitch_search(const opus_val16 *x_lp, opus_val16 *y,
|
||||||
|
int len, int max_pitch, int *pitch);
|
||||||
|
|
||||||
|
opus_val16 rnn_remove_doubling(opus_val16 *x, int maxperiod, int minperiod,
|
||||||
|
int N, int *T0, int prev_period, opus_val16 prev_gain);
|
||||||
|
|
||||||
|
|
||||||
|
/* OPT: This is the kernel you really want to optimize. It gets used a lot
|
||||||
|
by the prefilter and by the PLC. */
|
||||||
|
static OPUS_INLINE void xcorr_kernel(const opus_val16 * x, const opus_val16 * y, opus_val32 sum[4], int len)
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
opus_val16 y_0, y_1, y_2, y_3;
|
||||||
|
celt_assert(len>=3);
|
||||||
|
y_3=0; /* gcc doesn't realize that y_3 can't be used uninitialized */
|
||||||
|
y_0=*y++;
|
||||||
|
y_1=*y++;
|
||||||
|
y_2=*y++;
|
||||||
|
for (j=0;j<len-3;j+=4)
|
||||||
|
{
|
||||||
|
opus_val16 tmp;
|
||||||
|
tmp = *x++;
|
||||||
|
y_3=*y++;
|
||||||
|
sum[0] = MAC16_16(sum[0],tmp,y_0);
|
||||||
|
sum[1] = MAC16_16(sum[1],tmp,y_1);
|
||||||
|
sum[2] = MAC16_16(sum[2],tmp,y_2);
|
||||||
|
sum[3] = MAC16_16(sum[3],tmp,y_3);
|
||||||
|
tmp=*x++;
|
||||||
|
y_0=*y++;
|
||||||
|
sum[0] = MAC16_16(sum[0],tmp,y_1);
|
||||||
|
sum[1] = MAC16_16(sum[1],tmp,y_2);
|
||||||
|
sum[2] = MAC16_16(sum[2],tmp,y_3);
|
||||||
|
sum[3] = MAC16_16(sum[3],tmp,y_0);
|
||||||
|
tmp=*x++;
|
||||||
|
y_1=*y++;
|
||||||
|
sum[0] = MAC16_16(sum[0],tmp,y_2);
|
||||||
|
sum[1] = MAC16_16(sum[1],tmp,y_3);
|
||||||
|
sum[2] = MAC16_16(sum[2],tmp,y_0);
|
||||||
|
sum[3] = MAC16_16(sum[3],tmp,y_1);
|
||||||
|
tmp=*x++;
|
||||||
|
y_2=*y++;
|
||||||
|
sum[0] = MAC16_16(sum[0],tmp,y_3);
|
||||||
|
sum[1] = MAC16_16(sum[1],tmp,y_0);
|
||||||
|
sum[2] = MAC16_16(sum[2],tmp,y_1);
|
||||||
|
sum[3] = MAC16_16(sum[3],tmp,y_2);
|
||||||
|
}
|
||||||
|
if (j++<len)
|
||||||
|
{
|
||||||
|
opus_val16 tmp = *x++;
|
||||||
|
y_3=*y++;
|
||||||
|
sum[0] = MAC16_16(sum[0],tmp,y_0);
|
||||||
|
sum[1] = MAC16_16(sum[1],tmp,y_1);
|
||||||
|
sum[2] = MAC16_16(sum[2],tmp,y_2);
|
||||||
|
sum[3] = MAC16_16(sum[3],tmp,y_3);
|
||||||
|
}
|
||||||
|
if (j++<len)
|
||||||
|
{
|
||||||
|
opus_val16 tmp=*x++;
|
||||||
|
y_0=*y++;
|
||||||
|
sum[0] = MAC16_16(sum[0],tmp,y_1);
|
||||||
|
sum[1] = MAC16_16(sum[1],tmp,y_2);
|
||||||
|
sum[2] = MAC16_16(sum[2],tmp,y_3);
|
||||||
|
sum[3] = MAC16_16(sum[3],tmp,y_0);
|
||||||
|
}
|
||||||
|
if (j<len)
|
||||||
|
{
|
||||||
|
opus_val16 tmp=*x++;
|
||||||
|
y_1=*y++;
|
||||||
|
sum[0] = MAC16_16(sum[0],tmp,y_2);
|
||||||
|
sum[1] = MAC16_16(sum[1],tmp,y_3);
|
||||||
|
sum[2] = MAC16_16(sum[2],tmp,y_0);
|
||||||
|
sum[3] = MAC16_16(sum[3],tmp,y_1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static OPUS_INLINE void dual_inner_prod(const opus_val16 *x, const opus_val16 *y01, const opus_val16 *y02,
|
||||||
|
int N, opus_val32 *xy1, opus_val32 *xy2)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
opus_val32 xy01=0;
|
||||||
|
opus_val32 xy02=0;
|
||||||
|
for (i=0;i<N;i++)
|
||||||
|
{
|
||||||
|
xy01 = MAC16_16(xy01, x[i], y01[i]);
|
||||||
|
xy02 = MAC16_16(xy02, x[i], y02[i]);
|
||||||
|
}
|
||||||
|
*xy1 = xy01;
|
||||||
|
*xy2 = xy02;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*We make sure a C version is always available for cases where the overhead of
|
||||||
|
vectorization and passing around an arch flag aren't worth it.*/
|
||||||
|
static OPUS_INLINE opus_val32 celt_inner_prod(const opus_val16 *x,
|
||||||
|
const opus_val16 *y, int N)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
opus_val32 xy=0;
|
||||||
|
for (i=0;i<N;i++)
|
||||||
|
xy = MAC16_16(xy, x[i], y[i]);
|
||||||
|
return xy;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rnn_pitch_xcorr(const opus_val16 *_x, const opus_val16 *_y,
|
||||||
|
opus_val32 *xcorr, int len, int max_pitch);
|
||||||
|
|
||||||
|
#endif
|
||||||
60
third_party/rnnoise/src/rnn.c
vendored
Normal file
60
third_party/rnnoise/src/rnn.c
vendored
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/* Copyright (c) 2008-2011 Octasic Inc.
|
||||||
|
2012-2017 Jean-Marc Valin */
|
||||||
|
/*
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
- Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||||||
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include "opus_types.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "arch.h"
|
||||||
|
#include "rnn.h"
|
||||||
|
#include "rnnoise_data.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define INPUT_SIZE 42
|
||||||
|
|
||||||
|
|
||||||
|
void compute_rnn(const RNNoise *model, RNNState *rnn, float *gains, float *vad, const float *input, int arch) {
|
||||||
|
float tmp[MAX_NEURONS];
|
||||||
|
float cat[CONV2_OUT_SIZE + GRU1_OUT_SIZE + GRU2_OUT_SIZE + GRU3_OUT_SIZE];
|
||||||
|
/*for (int i=0;i<INPUT_SIZE;i++) printf("%f ", input[i]);printf("\n");*/
|
||||||
|
compute_generic_conv1d(&model->conv1, tmp, rnn->conv1_state, input, CONV1_IN_SIZE, ACTIVATION_TANH, arch);
|
||||||
|
compute_generic_conv1d(&model->conv2, cat, rnn->conv2_state, tmp, CONV2_IN_SIZE, ACTIVATION_TANH, arch);
|
||||||
|
compute_generic_gru(&model->gru1_input, &model->gru1_recurrent, rnn->gru1_state, cat, arch);
|
||||||
|
compute_generic_gru(&model->gru2_input, &model->gru2_recurrent, rnn->gru2_state, rnn->gru1_state, arch);
|
||||||
|
compute_generic_gru(&model->gru3_input, &model->gru3_recurrent, rnn->gru3_state, rnn->gru2_state, arch);
|
||||||
|
RNN_COPY(&cat[CONV2_OUT_SIZE], rnn->gru1_state, GRU1_OUT_SIZE);
|
||||||
|
RNN_COPY(&cat[CONV2_OUT_SIZE+GRU1_OUT_SIZE], rnn->gru2_state, GRU2_OUT_SIZE);
|
||||||
|
RNN_COPY(&cat[CONV2_OUT_SIZE+GRU1_OUT_SIZE+GRU2_OUT_SIZE], rnn->gru3_state, GRU3_OUT_SIZE);
|
||||||
|
compute_generic_dense(&model->dense_out, gains, cat, ACTIVATION_SIGMOID, arch);
|
||||||
|
compute_generic_dense(&model->vad_dense, vad, cat, ACTIVATION_SIGMOID, arch);
|
||||||
|
/*for (int i=0;i<22;i++) printf("%f ", gains[i]);printf("\n");*/
|
||||||
|
/*printf("%f\n", *vad);*/
|
||||||
|
}
|
||||||
49
third_party/rnnoise/src/rnn.h
vendored
Normal file
49
third_party/rnnoise/src/rnn.h
vendored
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/* Copyright (c) 2017 Jean-Marc Valin */
|
||||||
|
/*
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
- Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||||||
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RNN_H_
|
||||||
|
#define RNN_H_
|
||||||
|
|
||||||
|
#include "rnnoise.h"
|
||||||
|
#include "rnnoise_data.h"
|
||||||
|
|
||||||
|
#include "opus_types.h"
|
||||||
|
|
||||||
|
#define WEIGHTS_SCALE (1.f/256)
|
||||||
|
|
||||||
|
#define MAX_NEURONS 1024
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
float conv1_state[CONV1_STATE_SIZE];
|
||||||
|
float conv2_state[CONV2_STATE_SIZE];
|
||||||
|
float gru1_state[GRU1_STATE_SIZE];
|
||||||
|
float gru2_state[GRU2_STATE_SIZE];
|
||||||
|
float gru3_state[GRU3_STATE_SIZE];
|
||||||
|
} RNNState;
|
||||||
|
void compute_rnn(const RNNoise *model, RNNState *rnn, float *gains, float *vad, const float *input, int arch);
|
||||||
|
|
||||||
|
#endif /* RNN_H_ */
|
||||||
373966
third_party/rnnoise/src/rnnoise_data.c
vendored
Normal file
373966
third_party/rnnoise/src/rnnoise_data.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
55
third_party/rnnoise/src/rnnoise_data.h
vendored
Normal file
55
third_party/rnnoise/src/rnnoise_data.h
vendored
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
|
||||||
|
#ifndef RNNOISE_DATA_H
|
||||||
|
#define RNNOISE_DATA_H
|
||||||
|
|
||||||
|
#include "nnet.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define CONV1_OUT_SIZE 128
|
||||||
|
|
||||||
|
#define CONV1_IN_SIZE 65
|
||||||
|
|
||||||
|
#define CONV1_STATE_SIZE (65 * (2))
|
||||||
|
|
||||||
|
#define CONV1_DELAY 1
|
||||||
|
|
||||||
|
#define CONV2_OUT_SIZE 384
|
||||||
|
|
||||||
|
#define CONV2_IN_SIZE 128
|
||||||
|
|
||||||
|
#define CONV2_STATE_SIZE (128 * (2))
|
||||||
|
|
||||||
|
#define CONV2_DELAY 1
|
||||||
|
|
||||||
|
#define GRU1_OUT_SIZE 384
|
||||||
|
|
||||||
|
#define GRU1_STATE_SIZE 384
|
||||||
|
|
||||||
|
#define GRU2_OUT_SIZE 384
|
||||||
|
|
||||||
|
#define GRU2_STATE_SIZE 384
|
||||||
|
|
||||||
|
#define GRU3_OUT_SIZE 384
|
||||||
|
|
||||||
|
#define GRU3_STATE_SIZE 384
|
||||||
|
|
||||||
|
#define DENSE_OUT_OUT_SIZE 32
|
||||||
|
|
||||||
|
#define VAD_DENSE_OUT_SIZE 1
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
LinearLayer conv1;
|
||||||
|
LinearLayer conv2;
|
||||||
|
LinearLayer gru1_input;
|
||||||
|
LinearLayer gru1_recurrent;
|
||||||
|
LinearLayer gru2_input;
|
||||||
|
LinearLayer gru2_recurrent;
|
||||||
|
LinearLayer gru3_input;
|
||||||
|
LinearLayer gru3_recurrent;
|
||||||
|
LinearLayer dense_out;
|
||||||
|
LinearLayer vad_dense;
|
||||||
|
} RNNoise;
|
||||||
|
|
||||||
|
int init_rnnoise(RNNoise *model, const WeightArray *arrays);
|
||||||
|
|
||||||
|
#endif /* RNNOISE_DATA_H */
|
||||||
874
third_party/rnnoise/src/rnnoise_tables.c
vendored
Normal file
874
third_party/rnnoise/src/rnnoise_tables.c
vendored
Normal file
@@ -0,0 +1,874 @@
|
|||||||
|
/* The contents of this file was automatically generated by dump_rnnoise_tables.c*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
#include "kiss_fft.h"
|
||||||
|
|
||||||
|
static const arch_fft_state arch_fft = {0, NULL};
|
||||||
|
|
||||||
|
static const opus_int32 fft_bitrev[960] = {
|
||||||
|
0, 192, 384, 576, 768, 64, 256, 448, 640, 832, 128, 320, 512, 704, 896,
|
||||||
|
16, 208, 400, 592, 784, 80, 272, 464, 656, 848, 144, 336, 528, 720, 912,
|
||||||
|
32, 224, 416, 608, 800, 96, 288, 480, 672, 864, 160, 352, 544, 736, 928,
|
||||||
|
48, 240, 432, 624, 816, 112, 304, 496, 688, 880, 176, 368, 560, 752, 944,
|
||||||
|
4, 196, 388, 580, 772, 68, 260, 452, 644, 836, 132, 324, 516, 708, 900,
|
||||||
|
20, 212, 404, 596, 788, 84, 276, 468, 660, 852, 148, 340, 532, 724, 916,
|
||||||
|
36, 228, 420, 612, 804, 100, 292, 484, 676, 868, 164, 356, 548, 740, 932,
|
||||||
|
52, 244, 436, 628, 820, 116, 308, 500, 692, 884, 180, 372, 564, 756, 948,
|
||||||
|
8, 200, 392, 584, 776, 72, 264, 456, 648, 840, 136, 328, 520, 712, 904,
|
||||||
|
24, 216, 408, 600, 792, 88, 280, 472, 664, 856, 152, 344, 536, 728, 920,
|
||||||
|
40, 232, 424, 616, 808, 104, 296, 488, 680, 872, 168, 360, 552, 744, 936,
|
||||||
|
56, 248, 440, 632, 824, 120, 312, 504, 696, 888, 184, 376, 568, 760, 952,
|
||||||
|
12, 204, 396, 588, 780, 76, 268, 460, 652, 844, 140, 332, 524, 716, 908,
|
||||||
|
28, 220, 412, 604, 796, 92, 284, 476, 668, 860, 156, 348, 540, 732, 924,
|
||||||
|
44, 236, 428, 620, 812, 108, 300, 492, 684, 876, 172, 364, 556, 748, 940,
|
||||||
|
60, 252, 444, 636, 828, 124, 316, 508, 700, 892, 188, 380, 572, 764, 956,
|
||||||
|
1, 193, 385, 577, 769, 65, 257, 449, 641, 833, 129, 321, 513, 705, 897,
|
||||||
|
17, 209, 401, 593, 785, 81, 273, 465, 657, 849, 145, 337, 529, 721, 913,
|
||||||
|
33, 225, 417, 609, 801, 97, 289, 481, 673, 865, 161, 353, 545, 737, 929,
|
||||||
|
49, 241, 433, 625, 817, 113, 305, 497, 689, 881, 177, 369, 561, 753, 945,
|
||||||
|
5, 197, 389, 581, 773, 69, 261, 453, 645, 837, 133, 325, 517, 709, 901,
|
||||||
|
21, 213, 405, 597, 789, 85, 277, 469, 661, 853, 149, 341, 533, 725, 917,
|
||||||
|
37, 229, 421, 613, 805, 101, 293, 485, 677, 869, 165, 357, 549, 741, 933,
|
||||||
|
53, 245, 437, 629, 821, 117, 309, 501, 693, 885, 181, 373, 565, 757, 949,
|
||||||
|
9, 201, 393, 585, 777, 73, 265, 457, 649, 841, 137, 329, 521, 713, 905,
|
||||||
|
25, 217, 409, 601, 793, 89, 281, 473, 665, 857, 153, 345, 537, 729, 921,
|
||||||
|
41, 233, 425, 617, 809, 105, 297, 489, 681, 873, 169, 361, 553, 745, 937,
|
||||||
|
57, 249, 441, 633, 825, 121, 313, 505, 697, 889, 185, 377, 569, 761, 953,
|
||||||
|
13, 205, 397, 589, 781, 77, 269, 461, 653, 845, 141, 333, 525, 717, 909,
|
||||||
|
29, 221, 413, 605, 797, 93, 285, 477, 669, 861, 157, 349, 541, 733, 925,
|
||||||
|
45, 237, 429, 621, 813, 109, 301, 493, 685, 877, 173, 365, 557, 749, 941,
|
||||||
|
61, 253, 445, 637, 829, 125, 317, 509, 701, 893, 189, 381, 573, 765, 957,
|
||||||
|
2, 194, 386, 578, 770, 66, 258, 450, 642, 834, 130, 322, 514, 706, 898,
|
||||||
|
18, 210, 402, 594, 786, 82, 274, 466, 658, 850, 146, 338, 530, 722, 914,
|
||||||
|
34, 226, 418, 610, 802, 98, 290, 482, 674, 866, 162, 354, 546, 738, 930,
|
||||||
|
50, 242, 434, 626, 818, 114, 306, 498, 690, 882, 178, 370, 562, 754, 946,
|
||||||
|
6, 198, 390, 582, 774, 70, 262, 454, 646, 838, 134, 326, 518, 710, 902,
|
||||||
|
22, 214, 406, 598, 790, 86, 278, 470, 662, 854, 150, 342, 534, 726, 918,
|
||||||
|
38, 230, 422, 614, 806, 102, 294, 486, 678, 870, 166, 358, 550, 742, 934,
|
||||||
|
54, 246, 438, 630, 822, 118, 310, 502, 694, 886, 182, 374, 566, 758, 950,
|
||||||
|
10, 202, 394, 586, 778, 74, 266, 458, 650, 842, 138, 330, 522, 714, 906,
|
||||||
|
26, 218, 410, 602, 794, 90, 282, 474, 666, 858, 154, 346, 538, 730, 922,
|
||||||
|
42, 234, 426, 618, 810, 106, 298, 490, 682, 874, 170, 362, 554, 746, 938,
|
||||||
|
58, 250, 442, 634, 826, 122, 314, 506, 698, 890, 186, 378, 570, 762, 954,
|
||||||
|
14, 206, 398, 590, 782, 78, 270, 462, 654, 846, 142, 334, 526, 718, 910,
|
||||||
|
30, 222, 414, 606, 798, 94, 286, 478, 670, 862, 158, 350, 542, 734, 926,
|
||||||
|
46, 238, 430, 622, 814, 110, 302, 494, 686, 878, 174, 366, 558, 750, 942,
|
||||||
|
62, 254, 446, 638, 830, 126, 318, 510, 702, 894, 190, 382, 574, 766, 958,
|
||||||
|
3, 195, 387, 579, 771, 67, 259, 451, 643, 835, 131, 323, 515, 707, 899,
|
||||||
|
19, 211, 403, 595, 787, 83, 275, 467, 659, 851, 147, 339, 531, 723, 915,
|
||||||
|
35, 227, 419, 611, 803, 99, 291, 483, 675, 867, 163, 355, 547, 739, 931,
|
||||||
|
51, 243, 435, 627, 819, 115, 307, 499, 691, 883, 179, 371, 563, 755, 947,
|
||||||
|
7, 199, 391, 583, 775, 71, 263, 455, 647, 839, 135, 327, 519, 711, 903,
|
||||||
|
23, 215, 407, 599, 791, 87, 279, 471, 663, 855, 151, 343, 535, 727, 919,
|
||||||
|
39, 231, 423, 615, 807, 103, 295, 487, 679, 871, 167, 359, 551, 743, 935,
|
||||||
|
55, 247, 439, 631, 823, 119, 311, 503, 695, 887, 183, 375, 567, 759, 951,
|
||||||
|
11, 203, 395, 587, 779, 75, 267, 459, 651, 843, 139, 331, 523, 715, 907,
|
||||||
|
27, 219, 411, 603, 795, 91, 283, 475, 667, 859, 155, 347, 539, 731, 923,
|
||||||
|
43, 235, 427, 619, 811, 107, 299, 491, 683, 875, 171, 363, 555, 747, 939,
|
||||||
|
59, 251, 443, 635, 827, 123, 315, 507, 699, 891, 187, 379, 571, 763, 955,
|
||||||
|
15, 207, 399, 591, 783, 79, 271, 463, 655, 847, 143, 335, 527, 719, 911,
|
||||||
|
31, 223, 415, 607, 799, 95, 287, 479, 671, 863, 159, 351, 543, 735, 927,
|
||||||
|
47, 239, 431, 623, 815, 111, 303, 495, 687, 879, 175, 367, 559, 751, 943,
|
||||||
|
63, 255, 447, 639, 831, 127, 319, 511, 703, 895, 191, 383, 575, 767, 959,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const kiss_twiddle_cpx fft_twiddles[960] = {
|
||||||
|
{1.00000000f, -0.00000000f}, {0.999978602f, -0.00654493785f},
|
||||||
|
{0.999914348f, -0.0130895954f}, {0.999807239f, -0.0196336918f},
|
||||||
|
{0.999657333f, -0.0261769481f}, {0.999464571f, -0.0327190831f},
|
||||||
|
{0.999229014f, -0.0392598175f}, {0.998950660f, -0.0457988679f},
|
||||||
|
{0.998629510f, -0.0523359552f}, {0.998265624f, -0.0588708036f},
|
||||||
|
{0.997858942f, -0.0654031262f}, {0.997409463f, -0.0719326511f},
|
||||||
|
{0.996917307f, -0.0784590989f}, {0.996382475f, -0.0849821791f},
|
||||||
|
{0.995804906f, -0.0915016159f}, {0.995184720f, -0.0980171412f},
|
||||||
|
{0.994521916f, -0.104528464f}, {0.993816435f, -0.111035310f},
|
||||||
|
{0.993068457f, -0.117537394f}, {0.992277920f, -0.124034449f},
|
||||||
|
{0.991444886f, -0.130526185f}, {0.990569353f, -0.137012348f},
|
||||||
|
{0.989651382f, -0.143492624f}, {0.988691032f, -0.149966761f},
|
||||||
|
{0.987688363f, -0.156434461f}, {0.986643314f, -0.162895471f},
|
||||||
|
{0.985556066f, -0.169349506f}, {0.984426558f, -0.175796285f},
|
||||||
|
{0.983254910f, -0.182235524f}, {0.982041121f, -0.188666970f},
|
||||||
|
{0.980785251f, -0.195090324f}, {0.979487419f, -0.201505318f},
|
||||||
|
{0.978147626f, -0.207911685f}, {0.976765871f, -0.214309156f},
|
||||||
|
{0.975342333f, -0.220697433f}, {0.973876953f, -0.227076262f},
|
||||||
|
{0.972369909f, -0.233445361f}, {0.970821202f, -0.239804462f},
|
||||||
|
{0.969230890f, -0.246153295f}, {0.967599094f, -0.252491564f},
|
||||||
|
{0.965925813f, -0.258819044f}, {0.964211166f, -0.265135437f},
|
||||||
|
{0.962455213f, -0.271440446f}, {0.960658073f, -0.277733833f},
|
||||||
|
{0.958819747f, -0.284015357f}, {0.956940353f, -0.290284663f},
|
||||||
|
{0.955019951f, -0.296541572f}, {0.953058660f, -0.302785784f},
|
||||||
|
{0.951056540f, -0.309017003f}, {0.949013650f, -0.315234989f},
|
||||||
|
{0.946930110f, -0.321439475f}, {0.944806039f, -0.327630192f},
|
||||||
|
{0.942641497f, -0.333806872f}, {0.940436542f, -0.339969248f},
|
||||||
|
{0.938191354f, -0.346117049f}, {0.935905933f, -0.352250040f},
|
||||||
|
{0.933580399f, -0.358367950f}, {0.931214929f, -0.364470512f},
|
||||||
|
{0.928809524f, -0.370557427f}, {0.926364362f, -0.376628488f},
|
||||||
|
{0.923879504f, -0.382683426f}, {0.921355128f, -0.388721973f},
|
||||||
|
{0.918791234f, -0.394743860f}, {0.916187942f, -0.400748819f},
|
||||||
|
{0.913545430f, -0.406736642f}, {0.910863817f, -0.412707031f},
|
||||||
|
{0.908143163f, -0.418659747f}, {0.905383646f, -0.424594522f},
|
||||||
|
{0.902585268f, -0.430511087f}, {0.899748266f, -0.436409235f},
|
||||||
|
{0.896872759f, -0.442288697f}, {0.893958807f, -0.448149204f},
|
||||||
|
{0.891006529f, -0.453990489f}, {0.888016105f, -0.459812373f},
|
||||||
|
{0.884987652f, -0.465614527f}, {0.881921291f, -0.471396744f},
|
||||||
|
{0.878817141f, -0.477158755f}, {0.875675321f, -0.482900351f},
|
||||||
|
{0.872496009f, -0.488621235f}, {0.869279325f, -0.494321197f},
|
||||||
|
{0.866025388f, -0.500000000f}, {0.862734377f, -0.505657375f},
|
||||||
|
{0.859406412f, -0.511293113f}, {0.856041610f, -0.516906917f},
|
||||||
|
{0.852640152f, -0.522498548f}, {0.849202156f, -0.528067827f},
|
||||||
|
{0.845727801f, -0.533614516f}, {0.842217207f, -0.539138317f},
|
||||||
|
{0.838670552f, -0.544639051f}, {0.835087955f, -0.550116420f},
|
||||||
|
{0.831469595f, -0.555570245f}, {0.827815652f, -0.561000228f},
|
||||||
|
{0.824126184f, -0.566406250f}, {0.820401430f, -0.571787953f},
|
||||||
|
{0.816641569f, -0.577145219f}, {0.812846661f, -0.582477689f},
|
||||||
|
{0.809017003f, -0.587785244f}, {0.805152655f, -0.593067646f},
|
||||||
|
{0.801253796f, -0.598324597f}, {0.797320664f, -0.603555918f},
|
||||||
|
{0.793353319f, -0.608761430f}, {0.789352059f, -0.613940835f},
|
||||||
|
{0.785316944f, -0.619093955f}, {0.781248152f, -0.624220550f},
|
||||||
|
{0.777145982f, -0.629320383f}, {0.773010433f, -0.634393275f},
|
||||||
|
{0.768841803f, -0.639438987f}, {0.764640272f, -0.644457340f},
|
||||||
|
{0.760405958f, -0.649448037f}, {0.756139100f, -0.654410958f},
|
||||||
|
{0.751839817f, -0.659345806f}, {0.747508347f, -0.664252460f},
|
||||||
|
{0.743144810f, -0.669130623f}, {0.738749504f, -0.673980117f},
|
||||||
|
{0.734322488f, -0.678800762f}, {0.729864061f, -0.683592319f},
|
||||||
|
{0.725374401f, -0.688354552f}, {0.720853567f, -0.693087339f},
|
||||||
|
{0.716301918f, -0.697790444f}, {0.711719632f, -0.702463686f},
|
||||||
|
{0.707106769f, -0.707106769f}, {0.702463686f, -0.711719632f},
|
||||||
|
{0.697790444f, -0.716301918f}, {0.693087339f, -0.720853567f},
|
||||||
|
{0.688354552f, -0.725374401f}, {0.683592319f, -0.729864061f},
|
||||||
|
{0.678800762f, -0.734322488f}, {0.673980117f, -0.738749504f},
|
||||||
|
{0.669130623f, -0.743144810f}, {0.664252460f, -0.747508347f},
|
||||||
|
{0.659345806f, -0.751839817f}, {0.654410958f, -0.756139100f},
|
||||||
|
{0.649448037f, -0.760405958f}, {0.644457340f, -0.764640272f},
|
||||||
|
{0.639438987f, -0.768841803f}, {0.634393275f, -0.773010433f},
|
||||||
|
{0.629320383f, -0.777145982f}, {0.624220550f, -0.781248152f},
|
||||||
|
{0.619093955f, -0.785316944f}, {0.613940835f, -0.789352059f},
|
||||||
|
{0.608761430f, -0.793353319f}, {0.603555918f, -0.797320664f},
|
||||||
|
{0.598324597f, -0.801253796f}, {0.593067646f, -0.805152655f},
|
||||||
|
{0.587785244f, -0.809017003f}, {0.582477689f, -0.812846661f},
|
||||||
|
{0.577145219f, -0.816641569f}, {0.571787953f, -0.820401430f},
|
||||||
|
{0.566406250f, -0.824126184f}, {0.561000228f, -0.827815652f},
|
||||||
|
{0.555570245f, -0.831469595f}, {0.550116420f, -0.835087955f},
|
||||||
|
{0.544639051f, -0.838670552f}, {0.539138317f, -0.842217207f},
|
||||||
|
{0.533614516f, -0.845727801f}, {0.528067827f, -0.849202156f},
|
||||||
|
{0.522498548f, -0.852640152f}, {0.516906917f, -0.856041610f},
|
||||||
|
{0.511293113f, -0.859406412f}, {0.505657375f, -0.862734377f},
|
||||||
|
{0.500000000f, -0.866025388f}, {0.494321197f, -0.869279325f},
|
||||||
|
{0.488621235f, -0.872496009f}, {0.482900351f, -0.875675321f},
|
||||||
|
{0.477158755f, -0.878817141f}, {0.471396744f, -0.881921291f},
|
||||||
|
{0.465614527f, -0.884987652f}, {0.459812373f, -0.888016105f},
|
||||||
|
{0.453990489f, -0.891006529f}, {0.448149204f, -0.893958807f},
|
||||||
|
{0.442288697f, -0.896872759f}, {0.436409235f, -0.899748266f},
|
||||||
|
{0.430511087f, -0.902585268f}, {0.424594522f, -0.905383646f},
|
||||||
|
{0.418659747f, -0.908143163f}, {0.412707031f, -0.910863817f},
|
||||||
|
{0.406736642f, -0.913545430f}, {0.400748819f, -0.916187942f},
|
||||||
|
{0.394743860f, -0.918791234f}, {0.388721973f, -0.921355128f},
|
||||||
|
{0.382683426f, -0.923879504f}, {0.376628488f, -0.926364362f},
|
||||||
|
{0.370557427f, -0.928809524f}, {0.364470512f, -0.931214929f},
|
||||||
|
{0.358367950f, -0.933580399f}, {0.352250040f, -0.935905933f},
|
||||||
|
{0.346117049f, -0.938191354f}, {0.339969248f, -0.940436542f},
|
||||||
|
{0.333806872f, -0.942641497f}, {0.327630192f, -0.944806039f},
|
||||||
|
{0.321439475f, -0.946930110f}, {0.315234989f, -0.949013650f},
|
||||||
|
{0.309017003f, -0.951056540f}, {0.302785784f, -0.953058660f},
|
||||||
|
{0.296541572f, -0.955019951f}, {0.290284663f, -0.956940353f},
|
||||||
|
{0.284015357f, -0.958819747f}, {0.277733833f, -0.960658073f},
|
||||||
|
{0.271440446f, -0.962455213f}, {0.265135437f, -0.964211166f},
|
||||||
|
{0.258819044f, -0.965925813f}, {0.252491564f, -0.967599094f},
|
||||||
|
{0.246153295f, -0.969230890f}, {0.239804462f, -0.970821202f},
|
||||||
|
{0.233445361f, -0.972369909f}, {0.227076262f, -0.973876953f},
|
||||||
|
{0.220697433f, -0.975342333f}, {0.214309156f, -0.976765871f},
|
||||||
|
{0.207911685f, -0.978147626f}, {0.201505318f, -0.979487419f},
|
||||||
|
{0.195090324f, -0.980785251f}, {0.188666970f, -0.982041121f},
|
||||||
|
{0.182235524f, -0.983254910f}, {0.175796285f, -0.984426558f},
|
||||||
|
{0.169349506f, -0.985556066f}, {0.162895471f, -0.986643314f},
|
||||||
|
{0.156434461f, -0.987688363f}, {0.149966761f, -0.988691032f},
|
||||||
|
{0.143492624f, -0.989651382f}, {0.137012348f, -0.990569353f},
|
||||||
|
{0.130526185f, -0.991444886f}, {0.124034449f, -0.992277920f},
|
||||||
|
{0.117537394f, -0.993068457f}, {0.111035310f, -0.993816435f},
|
||||||
|
{0.104528464f, -0.994521916f}, {0.0980171412f, -0.995184720f},
|
||||||
|
{0.0915016159f, -0.995804906f}, {0.0849821791f, -0.996382475f},
|
||||||
|
{0.0784590989f, -0.996917307f}, {0.0719326511f, -0.997409463f},
|
||||||
|
{0.0654031262f, -0.997858942f}, {0.0588708036f, -0.998265624f},
|
||||||
|
{0.0523359552f, -0.998629510f}, {0.0457988679f, -0.998950660f},
|
||||||
|
{0.0392598175f, -0.999229014f}, {0.0327190831f, -0.999464571f},
|
||||||
|
{0.0261769481f, -0.999657333f}, {0.0196336918f, -0.999807239f},
|
||||||
|
{0.0130895954f, -0.999914348f}, {0.00654493785f, -0.999978602f},
|
||||||
|
{6.12323426e-17f, -1.00000000f}, {-0.00654493785f, -0.999978602f},
|
||||||
|
{-0.0130895954f, -0.999914348f}, {-0.0196336918f, -0.999807239f},
|
||||||
|
{-0.0261769481f, -0.999657333f}, {-0.0327190831f, -0.999464571f},
|
||||||
|
{-0.0392598175f, -0.999229014f}, {-0.0457988679f, -0.998950660f},
|
||||||
|
{-0.0523359552f, -0.998629510f}, {-0.0588708036f, -0.998265624f},
|
||||||
|
{-0.0654031262f, -0.997858942f}, {-0.0719326511f, -0.997409463f},
|
||||||
|
{-0.0784590989f, -0.996917307f}, {-0.0849821791f, -0.996382475f},
|
||||||
|
{-0.0915016159f, -0.995804906f}, {-0.0980171412f, -0.995184720f},
|
||||||
|
{-0.104528464f, -0.994521916f}, {-0.111035310f, -0.993816435f},
|
||||||
|
{-0.117537394f, -0.993068457f}, {-0.124034449f, -0.992277920f},
|
||||||
|
{-0.130526185f, -0.991444886f}, {-0.137012348f, -0.990569353f},
|
||||||
|
{-0.143492624f, -0.989651382f}, {-0.149966761f, -0.988691032f},
|
||||||
|
{-0.156434461f, -0.987688363f}, {-0.162895471f, -0.986643314f},
|
||||||
|
{-0.169349506f, -0.985556066f}, {-0.175796285f, -0.984426558f},
|
||||||
|
{-0.182235524f, -0.983254910f}, {-0.188666970f, -0.982041121f},
|
||||||
|
{-0.195090324f, -0.980785251f}, {-0.201505318f, -0.979487419f},
|
||||||
|
{-0.207911685f, -0.978147626f}, {-0.214309156f, -0.976765871f},
|
||||||
|
{-0.220697433f, -0.975342333f}, {-0.227076262f, -0.973876953f},
|
||||||
|
{-0.233445361f, -0.972369909f}, {-0.239804462f, -0.970821202f},
|
||||||
|
{-0.246153295f, -0.969230890f}, {-0.252491564f, -0.967599094f},
|
||||||
|
{-0.258819044f, -0.965925813f}, {-0.265135437f, -0.964211166f},
|
||||||
|
{-0.271440446f, -0.962455213f}, {-0.277733833f, -0.960658073f},
|
||||||
|
{-0.284015357f, -0.958819747f}, {-0.290284663f, -0.956940353f},
|
||||||
|
{-0.296541572f, -0.955019951f}, {-0.302785784f, -0.953058660f},
|
||||||
|
{-0.309017003f, -0.951056540f}, {-0.315234989f, -0.949013650f},
|
||||||
|
{-0.321439475f, -0.946930110f}, {-0.327630192f, -0.944806039f},
|
||||||
|
{-0.333806872f, -0.942641497f}, {-0.339969248f, -0.940436542f},
|
||||||
|
{-0.346117049f, -0.938191354f}, {-0.352250040f, -0.935905933f},
|
||||||
|
{-0.358367950f, -0.933580399f}, {-0.364470512f, -0.931214929f},
|
||||||
|
{-0.370557427f, -0.928809524f}, {-0.376628488f, -0.926364362f},
|
||||||
|
{-0.382683426f, -0.923879504f}, {-0.388721973f, -0.921355128f},
|
||||||
|
{-0.394743860f, -0.918791234f}, {-0.400748819f, -0.916187942f},
|
||||||
|
{-0.406736642f, -0.913545430f}, {-0.412707031f, -0.910863817f},
|
||||||
|
{-0.418659747f, -0.908143163f}, {-0.424594522f, -0.905383646f},
|
||||||
|
{-0.430511087f, -0.902585268f}, {-0.436409235f, -0.899748266f},
|
||||||
|
{-0.442288697f, -0.896872759f}, {-0.448149204f, -0.893958807f},
|
||||||
|
{-0.453990489f, -0.891006529f}, {-0.459812373f, -0.888016105f},
|
||||||
|
{-0.465614527f, -0.884987652f}, {-0.471396744f, -0.881921291f},
|
||||||
|
{-0.477158755f, -0.878817141f}, {-0.482900351f, -0.875675321f},
|
||||||
|
{-0.488621235f, -0.872496009f}, {-0.494321197f, -0.869279325f},
|
||||||
|
{-0.500000000f, -0.866025388f}, {-0.505657375f, -0.862734377f},
|
||||||
|
{-0.511293113f, -0.859406412f}, {-0.516906917f, -0.856041610f},
|
||||||
|
{-0.522498548f, -0.852640152f}, {-0.528067827f, -0.849202156f},
|
||||||
|
{-0.533614516f, -0.845727801f}, {-0.539138317f, -0.842217207f},
|
||||||
|
{-0.544639051f, -0.838670552f}, {-0.550116420f, -0.835087955f},
|
||||||
|
{-0.555570245f, -0.831469595f}, {-0.561000228f, -0.827815652f},
|
||||||
|
{-0.566406250f, -0.824126184f}, {-0.571787953f, -0.820401430f},
|
||||||
|
{-0.577145219f, -0.816641569f}, {-0.582477689f, -0.812846661f},
|
||||||
|
{-0.587785244f, -0.809017003f}, {-0.593067646f, -0.805152655f},
|
||||||
|
{-0.598324597f, -0.801253796f}, {-0.603555918f, -0.797320664f},
|
||||||
|
{-0.608761430f, -0.793353319f}, {-0.613940835f, -0.789352059f},
|
||||||
|
{-0.619093955f, -0.785316944f}, {-0.624220550f, -0.781248152f},
|
||||||
|
{-0.629320383f, -0.777145982f}, {-0.634393275f, -0.773010433f},
|
||||||
|
{-0.639438987f, -0.768841803f}, {-0.644457340f, -0.764640272f},
|
||||||
|
{-0.649448037f, -0.760405958f}, {-0.654410958f, -0.756139100f},
|
||||||
|
{-0.659345806f, -0.751839817f}, {-0.664252460f, -0.747508347f},
|
||||||
|
{-0.669130623f, -0.743144810f}, {-0.673980117f, -0.738749504f},
|
||||||
|
{-0.678800762f, -0.734322488f}, {-0.683592319f, -0.729864061f},
|
||||||
|
{-0.688354552f, -0.725374401f}, {-0.693087339f, -0.720853567f},
|
||||||
|
{-0.697790444f, -0.716301918f}, {-0.702463686f, -0.711719632f},
|
||||||
|
{-0.707106769f, -0.707106769f}, {-0.711719632f, -0.702463686f},
|
||||||
|
{-0.716301918f, -0.697790444f}, {-0.720853567f, -0.693087339f},
|
||||||
|
{-0.725374401f, -0.688354552f}, {-0.729864061f, -0.683592319f},
|
||||||
|
{-0.734322488f, -0.678800762f}, {-0.738749504f, -0.673980117f},
|
||||||
|
{-0.743144810f, -0.669130623f}, {-0.747508347f, -0.664252460f},
|
||||||
|
{-0.751839817f, -0.659345806f}, {-0.756139100f, -0.654410958f},
|
||||||
|
{-0.760405958f, -0.649448037f}, {-0.764640272f, -0.644457340f},
|
||||||
|
{-0.768841803f, -0.639438987f}, {-0.773010433f, -0.634393275f},
|
||||||
|
{-0.777145982f, -0.629320383f}, {-0.781248152f, -0.624220550f},
|
||||||
|
{-0.785316944f, -0.619093955f}, {-0.789352059f, -0.613940835f},
|
||||||
|
{-0.793353319f, -0.608761430f}, {-0.797320664f, -0.603555918f},
|
||||||
|
{-0.801253796f, -0.598324597f}, {-0.805152655f, -0.593067646f},
|
||||||
|
{-0.809017003f, -0.587785244f}, {-0.812846661f, -0.582477689f},
|
||||||
|
{-0.816641569f, -0.577145219f}, {-0.820401430f, -0.571787953f},
|
||||||
|
{-0.824126184f, -0.566406250f}, {-0.827815652f, -0.561000228f},
|
||||||
|
{-0.831469595f, -0.555570245f}, {-0.835087955f, -0.550116420f},
|
||||||
|
{-0.838670552f, -0.544639051f}, {-0.842217207f, -0.539138317f},
|
||||||
|
{-0.845727801f, -0.533614516f}, {-0.849202156f, -0.528067827f},
|
||||||
|
{-0.852640152f, -0.522498548f}, {-0.856041610f, -0.516906917f},
|
||||||
|
{-0.859406412f, -0.511293113f}, {-0.862734377f, -0.505657375f},
|
||||||
|
{-0.866025388f, -0.500000000f}, {-0.869279325f, -0.494321197f},
|
||||||
|
{-0.872496009f, -0.488621235f}, {-0.875675321f, -0.482900351f},
|
||||||
|
{-0.878817141f, -0.477158755f}, {-0.881921291f, -0.471396744f},
|
||||||
|
{-0.884987652f, -0.465614527f}, {-0.888016105f, -0.459812373f},
|
||||||
|
{-0.891006529f, -0.453990489f}, {-0.893958807f, -0.448149204f},
|
||||||
|
{-0.896872759f, -0.442288697f}, {-0.899748266f, -0.436409235f},
|
||||||
|
{-0.902585268f, -0.430511087f}, {-0.905383646f, -0.424594522f},
|
||||||
|
{-0.908143163f, -0.418659747f}, {-0.910863817f, -0.412707031f},
|
||||||
|
{-0.913545430f, -0.406736642f}, {-0.916187942f, -0.400748819f},
|
||||||
|
{-0.918791234f, -0.394743860f}, {-0.921355128f, -0.388721973f},
|
||||||
|
{-0.923879504f, -0.382683426f}, {-0.926364362f, -0.376628488f},
|
||||||
|
{-0.928809524f, -0.370557427f}, {-0.931214929f, -0.364470512f},
|
||||||
|
{-0.933580399f, -0.358367950f}, {-0.935905933f, -0.352250040f},
|
||||||
|
{-0.938191354f, -0.346117049f}, {-0.940436542f, -0.339969248f},
|
||||||
|
{-0.942641497f, -0.333806872f}, {-0.944806039f, -0.327630192f},
|
||||||
|
{-0.946930110f, -0.321439475f}, {-0.949013650f, -0.315234989f},
|
||||||
|
{-0.951056540f, -0.309017003f}, {-0.953058660f, -0.302785784f},
|
||||||
|
{-0.955019951f, -0.296541572f}, {-0.956940353f, -0.290284663f},
|
||||||
|
{-0.958819747f, -0.284015357f}, {-0.960658073f, -0.277733833f},
|
||||||
|
{-0.962455213f, -0.271440446f}, {-0.964211166f, -0.265135437f},
|
||||||
|
{-0.965925813f, -0.258819044f}, {-0.967599094f, -0.252491564f},
|
||||||
|
{-0.969230890f, -0.246153295f}, {-0.970821202f, -0.239804462f},
|
||||||
|
{-0.972369909f, -0.233445361f}, {-0.973876953f, -0.227076262f},
|
||||||
|
{-0.975342333f, -0.220697433f}, {-0.976765871f, -0.214309156f},
|
||||||
|
{-0.978147626f, -0.207911685f}, {-0.979487419f, -0.201505318f},
|
||||||
|
{-0.980785251f, -0.195090324f}, {-0.982041121f, -0.188666970f},
|
||||||
|
{-0.983254910f, -0.182235524f}, {-0.984426558f, -0.175796285f},
|
||||||
|
{-0.985556066f, -0.169349506f}, {-0.986643314f, -0.162895471f},
|
||||||
|
{-0.987688363f, -0.156434461f}, {-0.988691032f, -0.149966761f},
|
||||||
|
{-0.989651382f, -0.143492624f}, {-0.990569353f, -0.137012348f},
|
||||||
|
{-0.991444886f, -0.130526185f}, {-0.992277920f, -0.124034449f},
|
||||||
|
{-0.993068457f, -0.117537394f}, {-0.993816435f, -0.111035310f},
|
||||||
|
{-0.994521916f, -0.104528464f}, {-0.995184720f, -0.0980171412f},
|
||||||
|
{-0.995804906f, -0.0915016159f}, {-0.996382475f, -0.0849821791f},
|
||||||
|
{-0.996917307f, -0.0784590989f}, {-0.997409463f, -0.0719326511f},
|
||||||
|
{-0.997858942f, -0.0654031262f}, {-0.998265624f, -0.0588708036f},
|
||||||
|
{-0.998629510f, -0.0523359552f}, {-0.998950660f, -0.0457988679f},
|
||||||
|
{-0.999229014f, -0.0392598175f}, {-0.999464571f, -0.0327190831f},
|
||||||
|
{-0.999657333f, -0.0261769481f}, {-0.999807239f, -0.0196336918f},
|
||||||
|
{-0.999914348f, -0.0130895954f}, {-0.999978602f, -0.00654493785f},
|
||||||
|
{-1.00000000f, -1.22464685e-16f}, {-0.999978602f, 0.00654493785f},
|
||||||
|
{-0.999914348f, 0.0130895954f}, {-0.999807239f, 0.0196336918f},
|
||||||
|
{-0.999657333f, 0.0261769481f}, {-0.999464571f, 0.0327190831f},
|
||||||
|
{-0.999229014f, 0.0392598175f}, {-0.998950660f, 0.0457988679f},
|
||||||
|
{-0.998629510f, 0.0523359552f}, {-0.998265624f, 0.0588708036f},
|
||||||
|
{-0.997858942f, 0.0654031262f}, {-0.997409463f, 0.0719326511f},
|
||||||
|
{-0.996917307f, 0.0784590989f}, {-0.996382475f, 0.0849821791f},
|
||||||
|
{-0.995804906f, 0.0915016159f}, {-0.995184720f, 0.0980171412f},
|
||||||
|
{-0.994521916f, 0.104528464f}, {-0.993816435f, 0.111035310f},
|
||||||
|
{-0.993068457f, 0.117537394f}, {-0.992277920f, 0.124034449f},
|
||||||
|
{-0.991444886f, 0.130526185f}, {-0.990569353f, 0.137012348f},
|
||||||
|
{-0.989651382f, 0.143492624f}, {-0.988691032f, 0.149966761f},
|
||||||
|
{-0.987688363f, 0.156434461f}, {-0.986643314f, 0.162895471f},
|
||||||
|
{-0.985556066f, 0.169349506f}, {-0.984426558f, 0.175796285f},
|
||||||
|
{-0.983254910f, 0.182235524f}, {-0.982041121f, 0.188666970f},
|
||||||
|
{-0.980785251f, 0.195090324f}, {-0.979487419f, 0.201505318f},
|
||||||
|
{-0.978147626f, 0.207911685f}, {-0.976765871f, 0.214309156f},
|
||||||
|
{-0.975342333f, 0.220697433f}, {-0.973876953f, 0.227076262f},
|
||||||
|
{-0.972369909f, 0.233445361f}, {-0.970821202f, 0.239804462f},
|
||||||
|
{-0.969230890f, 0.246153295f}, {-0.967599094f, 0.252491564f},
|
||||||
|
{-0.965925813f, 0.258819044f}, {-0.964211166f, 0.265135437f},
|
||||||
|
{-0.962455213f, 0.271440446f}, {-0.960658073f, 0.277733833f},
|
||||||
|
{-0.958819747f, 0.284015357f}, {-0.956940353f, 0.290284663f},
|
||||||
|
{-0.955019951f, 0.296541572f}, {-0.953058660f, 0.302785784f},
|
||||||
|
{-0.951056540f, 0.309017003f}, {-0.949013650f, 0.315234989f},
|
||||||
|
{-0.946930110f, 0.321439475f}, {-0.944806039f, 0.327630192f},
|
||||||
|
{-0.942641497f, 0.333806872f}, {-0.940436542f, 0.339969248f},
|
||||||
|
{-0.938191354f, 0.346117049f}, {-0.935905933f, 0.352250040f},
|
||||||
|
{-0.933580399f, 0.358367950f}, {-0.931214929f, 0.364470512f},
|
||||||
|
{-0.928809524f, 0.370557427f}, {-0.926364362f, 0.376628488f},
|
||||||
|
{-0.923879504f, 0.382683426f}, {-0.921355128f, 0.388721973f},
|
||||||
|
{-0.918791234f, 0.394743860f}, {-0.916187942f, 0.400748819f},
|
||||||
|
{-0.913545430f, 0.406736642f}, {-0.910863817f, 0.412707031f},
|
||||||
|
{-0.908143163f, 0.418659747f}, {-0.905383646f, 0.424594522f},
|
||||||
|
{-0.902585268f, 0.430511087f}, {-0.899748266f, 0.436409235f},
|
||||||
|
{-0.896872759f, 0.442288697f}, {-0.893958807f, 0.448149204f},
|
||||||
|
{-0.891006529f, 0.453990489f}, {-0.888016105f, 0.459812373f},
|
||||||
|
{-0.884987652f, 0.465614527f}, {-0.881921291f, 0.471396744f},
|
||||||
|
{-0.878817141f, 0.477158755f}, {-0.875675321f, 0.482900351f},
|
||||||
|
{-0.872496009f, 0.488621235f}, {-0.869279325f, 0.494321197f},
|
||||||
|
{-0.866025388f, 0.500000000f}, {-0.862734377f, 0.505657375f},
|
||||||
|
{-0.859406412f, 0.511293113f}, {-0.856041610f, 0.516906917f},
|
||||||
|
{-0.852640152f, 0.522498548f}, {-0.849202156f, 0.528067827f},
|
||||||
|
{-0.845727801f, 0.533614516f}, {-0.842217207f, 0.539138317f},
|
||||||
|
{-0.838670552f, 0.544639051f}, {-0.835087955f, 0.550116420f},
|
||||||
|
{-0.831469595f, 0.555570245f}, {-0.827815652f, 0.561000228f},
|
||||||
|
{-0.824126184f, 0.566406250f}, {-0.820401430f, 0.571787953f},
|
||||||
|
{-0.816641569f, 0.577145219f}, {-0.812846661f, 0.582477689f},
|
||||||
|
{-0.809017003f, 0.587785244f}, {-0.805152655f, 0.593067646f},
|
||||||
|
{-0.801253796f, 0.598324597f}, {-0.797320664f, 0.603555918f},
|
||||||
|
{-0.793353319f, 0.608761430f}, {-0.789352059f, 0.613940835f},
|
||||||
|
{-0.785316944f, 0.619093955f}, {-0.781248152f, 0.624220550f},
|
||||||
|
{-0.777145982f, 0.629320383f}, {-0.773010433f, 0.634393275f},
|
||||||
|
{-0.768841803f, 0.639438987f}, {-0.764640272f, 0.644457340f},
|
||||||
|
{-0.760405958f, 0.649448037f}, {-0.756139100f, 0.654410958f},
|
||||||
|
{-0.751839817f, 0.659345806f}, {-0.747508347f, 0.664252460f},
|
||||||
|
{-0.743144810f, 0.669130623f}, {-0.738749504f, 0.673980117f},
|
||||||
|
{-0.734322488f, 0.678800762f}, {-0.729864061f, 0.683592319f},
|
||||||
|
{-0.725374401f, 0.688354552f}, {-0.720853567f, 0.693087339f},
|
||||||
|
{-0.716301918f, 0.697790444f}, {-0.711719632f, 0.702463686f},
|
||||||
|
{-0.707106769f, 0.707106769f}, {-0.702463686f, 0.711719632f},
|
||||||
|
{-0.697790444f, 0.716301918f}, {-0.693087339f, 0.720853567f},
|
||||||
|
{-0.688354552f, 0.725374401f}, {-0.683592319f, 0.729864061f},
|
||||||
|
{-0.678800762f, 0.734322488f}, {-0.673980117f, 0.738749504f},
|
||||||
|
{-0.669130623f, 0.743144810f}, {-0.664252460f, 0.747508347f},
|
||||||
|
{-0.659345806f, 0.751839817f}, {-0.654410958f, 0.756139100f},
|
||||||
|
{-0.649448037f, 0.760405958f}, {-0.644457340f, 0.764640272f},
|
||||||
|
{-0.639438987f, 0.768841803f}, {-0.634393275f, 0.773010433f},
|
||||||
|
{-0.629320383f, 0.777145982f}, {-0.624220550f, 0.781248152f},
|
||||||
|
{-0.619093955f, 0.785316944f}, {-0.613940835f, 0.789352059f},
|
||||||
|
{-0.608761430f, 0.793353319f}, {-0.603555918f, 0.797320664f},
|
||||||
|
{-0.598324597f, 0.801253796f}, {-0.593067646f, 0.805152655f},
|
||||||
|
{-0.587785244f, 0.809017003f}, {-0.582477689f, 0.812846661f},
|
||||||
|
{-0.577145219f, 0.816641569f}, {-0.571787953f, 0.820401430f},
|
||||||
|
{-0.566406250f, 0.824126184f}, {-0.561000228f, 0.827815652f},
|
||||||
|
{-0.555570245f, 0.831469595f}, {-0.550116420f, 0.835087955f},
|
||||||
|
{-0.544639051f, 0.838670552f}, {-0.539138317f, 0.842217207f},
|
||||||
|
{-0.533614516f, 0.845727801f}, {-0.528067827f, 0.849202156f},
|
||||||
|
{-0.522498548f, 0.852640152f}, {-0.516906917f, 0.856041610f},
|
||||||
|
{-0.511293113f, 0.859406412f}, {-0.505657375f, 0.862734377f},
|
||||||
|
{-0.500000000f, 0.866025388f}, {-0.494321197f, 0.869279325f},
|
||||||
|
{-0.488621235f, 0.872496009f}, {-0.482900351f, 0.875675321f},
|
||||||
|
{-0.477158755f, 0.878817141f}, {-0.471396744f, 0.881921291f},
|
||||||
|
{-0.465614527f, 0.884987652f}, {-0.459812373f, 0.888016105f},
|
||||||
|
{-0.453990489f, 0.891006529f}, {-0.448149204f, 0.893958807f},
|
||||||
|
{-0.442288697f, 0.896872759f}, {-0.436409235f, 0.899748266f},
|
||||||
|
{-0.430511087f, 0.902585268f}, {-0.424594522f, 0.905383646f},
|
||||||
|
{-0.418659747f, 0.908143163f}, {-0.412707031f, 0.910863817f},
|
||||||
|
{-0.406736642f, 0.913545430f}, {-0.400748819f, 0.916187942f},
|
||||||
|
{-0.394743860f, 0.918791234f}, {-0.388721973f, 0.921355128f},
|
||||||
|
{-0.382683426f, 0.923879504f}, {-0.376628488f, 0.926364362f},
|
||||||
|
{-0.370557427f, 0.928809524f}, {-0.364470512f, 0.931214929f},
|
||||||
|
{-0.358367950f, 0.933580399f}, {-0.352250040f, 0.935905933f},
|
||||||
|
{-0.346117049f, 0.938191354f}, {-0.339969248f, 0.940436542f},
|
||||||
|
{-0.333806872f, 0.942641497f}, {-0.327630192f, 0.944806039f},
|
||||||
|
{-0.321439475f, 0.946930110f}, {-0.315234989f, 0.949013650f},
|
||||||
|
{-0.309017003f, 0.951056540f}, {-0.302785784f, 0.953058660f},
|
||||||
|
{-0.296541572f, 0.955019951f}, {-0.290284663f, 0.956940353f},
|
||||||
|
{-0.284015357f, 0.958819747f}, {-0.277733833f, 0.960658073f},
|
||||||
|
{-0.271440446f, 0.962455213f}, {-0.265135437f, 0.964211166f},
|
||||||
|
{-0.258819044f, 0.965925813f}, {-0.252491564f, 0.967599094f},
|
||||||
|
{-0.246153295f, 0.969230890f}, {-0.239804462f, 0.970821202f},
|
||||||
|
{-0.233445361f, 0.972369909f}, {-0.227076262f, 0.973876953f},
|
||||||
|
{-0.220697433f, 0.975342333f}, {-0.214309156f, 0.976765871f},
|
||||||
|
{-0.207911685f, 0.978147626f}, {-0.201505318f, 0.979487419f},
|
||||||
|
{-0.195090324f, 0.980785251f}, {-0.188666970f, 0.982041121f},
|
||||||
|
{-0.182235524f, 0.983254910f}, {-0.175796285f, 0.984426558f},
|
||||||
|
{-0.169349506f, 0.985556066f}, {-0.162895471f, 0.986643314f},
|
||||||
|
{-0.156434461f, 0.987688363f}, {-0.149966761f, 0.988691032f},
|
||||||
|
{-0.143492624f, 0.989651382f}, {-0.137012348f, 0.990569353f},
|
||||||
|
{-0.130526185f, 0.991444886f}, {-0.124034449f, 0.992277920f},
|
||||||
|
{-0.117537394f, 0.993068457f}, {-0.111035310f, 0.993816435f},
|
||||||
|
{-0.104528464f, 0.994521916f}, {-0.0980171412f, 0.995184720f},
|
||||||
|
{-0.0915016159f, 0.995804906f}, {-0.0849821791f, 0.996382475f},
|
||||||
|
{-0.0784590989f, 0.996917307f}, {-0.0719326511f, 0.997409463f},
|
||||||
|
{-0.0654031262f, 0.997858942f}, {-0.0588708036f, 0.998265624f},
|
||||||
|
{-0.0523359552f, 0.998629510f}, {-0.0457988679f, 0.998950660f},
|
||||||
|
{-0.0392598175f, 0.999229014f}, {-0.0327190831f, 0.999464571f},
|
||||||
|
{-0.0261769481f, 0.999657333f}, {-0.0196336918f, 0.999807239f},
|
||||||
|
{-0.0130895954f, 0.999914348f}, {-0.00654493785f, 0.999978602f},
|
||||||
|
{-1.83697015e-16f, 1.00000000f}, {0.00654493785f, 0.999978602f},
|
||||||
|
{0.0130895954f, 0.999914348f}, {0.0196336918f, 0.999807239f},
|
||||||
|
{0.0261769481f, 0.999657333f}, {0.0327190831f, 0.999464571f},
|
||||||
|
{0.0392598175f, 0.999229014f}, {0.0457988679f, 0.998950660f},
|
||||||
|
{0.0523359552f, 0.998629510f}, {0.0588708036f, 0.998265624f},
|
||||||
|
{0.0654031262f, 0.997858942f}, {0.0719326511f, 0.997409463f},
|
||||||
|
{0.0784590989f, 0.996917307f}, {0.0849821791f, 0.996382475f},
|
||||||
|
{0.0915016159f, 0.995804906f}, {0.0980171412f, 0.995184720f},
|
||||||
|
{0.104528464f, 0.994521916f}, {0.111035310f, 0.993816435f},
|
||||||
|
{0.117537394f, 0.993068457f}, {0.124034449f, 0.992277920f},
|
||||||
|
{0.130526185f, 0.991444886f}, {0.137012348f, 0.990569353f},
|
||||||
|
{0.143492624f, 0.989651382f}, {0.149966761f, 0.988691032f},
|
||||||
|
{0.156434461f, 0.987688363f}, {0.162895471f, 0.986643314f},
|
||||||
|
{0.169349506f, 0.985556066f}, {0.175796285f, 0.984426558f},
|
||||||
|
{0.182235524f, 0.983254910f}, {0.188666970f, 0.982041121f},
|
||||||
|
{0.195090324f, 0.980785251f}, {0.201505318f, 0.979487419f},
|
||||||
|
{0.207911685f, 0.978147626f}, {0.214309156f, 0.976765871f},
|
||||||
|
{0.220697433f, 0.975342333f}, {0.227076262f, 0.973876953f},
|
||||||
|
{0.233445361f, 0.972369909f}, {0.239804462f, 0.970821202f},
|
||||||
|
{0.246153295f, 0.969230890f}, {0.252491564f, 0.967599094f},
|
||||||
|
{0.258819044f, 0.965925813f}, {0.265135437f, 0.964211166f},
|
||||||
|
{0.271440446f, 0.962455213f}, {0.277733833f, 0.960658073f},
|
||||||
|
{0.284015357f, 0.958819747f}, {0.290284663f, 0.956940353f},
|
||||||
|
{0.296541572f, 0.955019951f}, {0.302785784f, 0.953058660f},
|
||||||
|
{0.309017003f, 0.951056540f}, {0.315234989f, 0.949013650f},
|
||||||
|
{0.321439475f, 0.946930110f}, {0.327630192f, 0.944806039f},
|
||||||
|
{0.333806872f, 0.942641497f}, {0.339969248f, 0.940436542f},
|
||||||
|
{0.346117049f, 0.938191354f}, {0.352250040f, 0.935905933f},
|
||||||
|
{0.358367950f, 0.933580399f}, {0.364470512f, 0.931214929f},
|
||||||
|
{0.370557427f, 0.928809524f}, {0.376628488f, 0.926364362f},
|
||||||
|
{0.382683426f, 0.923879504f}, {0.388721973f, 0.921355128f},
|
||||||
|
{0.394743860f, 0.918791234f}, {0.400748819f, 0.916187942f},
|
||||||
|
{0.406736642f, 0.913545430f}, {0.412707031f, 0.910863817f},
|
||||||
|
{0.418659747f, 0.908143163f}, {0.424594522f, 0.905383646f},
|
||||||
|
{0.430511087f, 0.902585268f}, {0.436409235f, 0.899748266f},
|
||||||
|
{0.442288697f, 0.896872759f}, {0.448149204f, 0.893958807f},
|
||||||
|
{0.453990489f, 0.891006529f}, {0.459812373f, 0.888016105f},
|
||||||
|
{0.465614527f, 0.884987652f}, {0.471396744f, 0.881921291f},
|
||||||
|
{0.477158755f, 0.878817141f}, {0.482900351f, 0.875675321f},
|
||||||
|
{0.488621235f, 0.872496009f}, {0.494321197f, 0.869279325f},
|
||||||
|
{0.500000000f, 0.866025388f}, {0.505657375f, 0.862734377f},
|
||||||
|
{0.511293113f, 0.859406412f}, {0.516906917f, 0.856041610f},
|
||||||
|
{0.522498548f, 0.852640152f}, {0.528067827f, 0.849202156f},
|
||||||
|
{0.533614516f, 0.845727801f}, {0.539138317f, 0.842217207f},
|
||||||
|
{0.544639051f, 0.838670552f}, {0.550116420f, 0.835087955f},
|
||||||
|
{0.555570245f, 0.831469595f}, {0.561000228f, 0.827815652f},
|
||||||
|
{0.566406250f, 0.824126184f}, {0.571787953f, 0.820401430f},
|
||||||
|
{0.577145219f, 0.816641569f}, {0.582477689f, 0.812846661f},
|
||||||
|
{0.587785244f, 0.809017003f}, {0.593067646f, 0.805152655f},
|
||||||
|
{0.598324597f, 0.801253796f}, {0.603555918f, 0.797320664f},
|
||||||
|
{0.608761430f, 0.793353319f}, {0.613940835f, 0.789352059f},
|
||||||
|
{0.619093955f, 0.785316944f}, {0.624220550f, 0.781248152f},
|
||||||
|
{0.629320383f, 0.777145982f}, {0.634393275f, 0.773010433f},
|
||||||
|
{0.639438987f, 0.768841803f}, {0.644457340f, 0.764640272f},
|
||||||
|
{0.649448037f, 0.760405958f}, {0.654410958f, 0.756139100f},
|
||||||
|
{0.659345806f, 0.751839817f}, {0.664252460f, 0.747508347f},
|
||||||
|
{0.669130623f, 0.743144810f}, {0.673980117f, 0.738749504f},
|
||||||
|
{0.678800762f, 0.734322488f}, {0.683592319f, 0.729864061f},
|
||||||
|
{0.688354552f, 0.725374401f}, {0.693087339f, 0.720853567f},
|
||||||
|
{0.697790444f, 0.716301918f}, {0.702463686f, 0.711719632f},
|
||||||
|
{0.707106769f, 0.707106769f}, {0.711719632f, 0.702463686f},
|
||||||
|
{0.716301918f, 0.697790444f}, {0.720853567f, 0.693087339f},
|
||||||
|
{0.725374401f, 0.688354552f}, {0.729864061f, 0.683592319f},
|
||||||
|
{0.734322488f, 0.678800762f}, {0.738749504f, 0.673980117f},
|
||||||
|
{0.743144810f, 0.669130623f}, {0.747508347f, 0.664252460f},
|
||||||
|
{0.751839817f, 0.659345806f}, {0.756139100f, 0.654410958f},
|
||||||
|
{0.760405958f, 0.649448037f}, {0.764640272f, 0.644457340f},
|
||||||
|
{0.768841803f, 0.639438987f}, {0.773010433f, 0.634393275f},
|
||||||
|
{0.777145982f, 0.629320383f}, {0.781248152f, 0.624220550f},
|
||||||
|
{0.785316944f, 0.619093955f}, {0.789352059f, 0.613940835f},
|
||||||
|
{0.793353319f, 0.608761430f}, {0.797320664f, 0.603555918f},
|
||||||
|
{0.801253796f, 0.598324597f}, {0.805152655f, 0.593067646f},
|
||||||
|
{0.809017003f, 0.587785244f}, {0.812846661f, 0.582477689f},
|
||||||
|
{0.816641569f, 0.577145219f}, {0.820401430f, 0.571787953f},
|
||||||
|
{0.824126184f, 0.566406250f}, {0.827815652f, 0.561000228f},
|
||||||
|
{0.831469595f, 0.555570245f}, {0.835087955f, 0.550116420f},
|
||||||
|
{0.838670552f, 0.544639051f}, {0.842217207f, 0.539138317f},
|
||||||
|
{0.845727801f, 0.533614516f}, {0.849202156f, 0.528067827f},
|
||||||
|
{0.852640152f, 0.522498548f}, {0.856041610f, 0.516906917f},
|
||||||
|
{0.859406412f, 0.511293113f}, {0.862734377f, 0.505657375f},
|
||||||
|
{0.866025388f, 0.500000000f}, {0.869279325f, 0.494321197f},
|
||||||
|
{0.872496009f, 0.488621235f}, {0.875675321f, 0.482900351f},
|
||||||
|
{0.878817141f, 0.477158755f}, {0.881921291f, 0.471396744f},
|
||||||
|
{0.884987652f, 0.465614527f}, {0.888016105f, 0.459812373f},
|
||||||
|
{0.891006529f, 0.453990489f}, {0.893958807f, 0.448149204f},
|
||||||
|
{0.896872759f, 0.442288697f}, {0.899748266f, 0.436409235f},
|
||||||
|
{0.902585268f, 0.430511087f}, {0.905383646f, 0.424594522f},
|
||||||
|
{0.908143163f, 0.418659747f}, {0.910863817f, 0.412707031f},
|
||||||
|
{0.913545430f, 0.406736642f}, {0.916187942f, 0.400748819f},
|
||||||
|
{0.918791234f, 0.394743860f}, {0.921355128f, 0.388721973f},
|
||||||
|
{0.923879504f, 0.382683426f}, {0.926364362f, 0.376628488f},
|
||||||
|
{0.928809524f, 0.370557427f}, {0.931214929f, 0.364470512f},
|
||||||
|
{0.933580399f, 0.358367950f}, {0.935905933f, 0.352250040f},
|
||||||
|
{0.938191354f, 0.346117049f}, {0.940436542f, 0.339969248f},
|
||||||
|
{0.942641497f, 0.333806872f}, {0.944806039f, 0.327630192f},
|
||||||
|
{0.946930110f, 0.321439475f}, {0.949013650f, 0.315234989f},
|
||||||
|
{0.951056540f, 0.309017003f}, {0.953058660f, 0.302785784f},
|
||||||
|
{0.955019951f, 0.296541572f}, {0.956940353f, 0.290284663f},
|
||||||
|
{0.958819747f, 0.284015357f}, {0.960658073f, 0.277733833f},
|
||||||
|
{0.962455213f, 0.271440446f}, {0.964211166f, 0.265135437f},
|
||||||
|
{0.965925813f, 0.258819044f}, {0.967599094f, 0.252491564f},
|
||||||
|
{0.969230890f, 0.246153295f}, {0.970821202f, 0.239804462f},
|
||||||
|
{0.972369909f, 0.233445361f}, {0.973876953f, 0.227076262f},
|
||||||
|
{0.975342333f, 0.220697433f}, {0.976765871f, 0.214309156f},
|
||||||
|
{0.978147626f, 0.207911685f}, {0.979487419f, 0.201505318f},
|
||||||
|
{0.980785251f, 0.195090324f}, {0.982041121f, 0.188666970f},
|
||||||
|
{0.983254910f, 0.182235524f}, {0.984426558f, 0.175796285f},
|
||||||
|
{0.985556066f, 0.169349506f}, {0.986643314f, 0.162895471f},
|
||||||
|
{0.987688363f, 0.156434461f}, {0.988691032f, 0.149966761f},
|
||||||
|
{0.989651382f, 0.143492624f}, {0.990569353f, 0.137012348f},
|
||||||
|
{0.991444886f, 0.130526185f}, {0.992277920f, 0.124034449f},
|
||||||
|
{0.993068457f, 0.117537394f}, {0.993816435f, 0.111035310f},
|
||||||
|
{0.994521916f, 0.104528464f}, {0.995184720f, 0.0980171412f},
|
||||||
|
{0.995804906f, 0.0915016159f}, {0.996382475f, 0.0849821791f},
|
||||||
|
{0.996917307f, 0.0784590989f}, {0.997409463f, 0.0719326511f},
|
||||||
|
{0.997858942f, 0.0654031262f}, {0.998265624f, 0.0588708036f},
|
||||||
|
{0.998629510f, 0.0523359552f}, {0.998950660f, 0.0457988679f},
|
||||||
|
{0.999229014f, 0.0392598175f}, {0.999464571f, 0.0327190831f},
|
||||||
|
{0.999657333f, 0.0261769481f}, {0.999807239f, 0.0196336918f},
|
||||||
|
{0.999914348f, 0.0130895954f}, {0.999978602f, 0.00654493785f},
|
||||||
|
};
|
||||||
|
|
||||||
|
const kiss_fft_state rnn_kfft = {
|
||||||
|
960, /* nfft */
|
||||||
|
0.0010416667f, /* scale */
|
||||||
|
-1, /* shift */
|
||||||
|
{5, 192, 3, 64, 4, 16, 4, 4, 4, 1, 0, 0, 0, 0, 0, 0, }, /* factors */
|
||||||
|
fft_bitrev, /* bitrev*/
|
||||||
|
fft_twiddles, /* twiddles*/
|
||||||
|
(arch_fft_state *)&arch_fft, /* arch_fft*/
|
||||||
|
};
|
||||||
|
|
||||||
|
const float rnn_half_window[] = {
|
||||||
|
4.20549168e-06f, 3.78491532e-05f, 0.000105135041f, 0.000206060256f, 0.000340620492f,
|
||||||
|
0.000508809986f, 0.000710621476f, 0.000946046319f, 0.00121507444f, 0.00151769421f,
|
||||||
|
0.00185389258f, 0.00222365512f, 0.00262696599f, 0.00306380726f, 0.00353416055f,
|
||||||
|
0.00403800514f, 0.00457531959f, 0.00514607970f, 0.00575026125f, 0.00638783723f,
|
||||||
|
0.00705878017f, 0.00776306028f, 0.00850064680f, 0.00927150715f, 0.0100756064f,
|
||||||
|
0.0109129101f, 0.0117833801f, 0.0126869772f, 0.0136236614f, 0.0145933898f,
|
||||||
|
0.0155961197f, 0.0166318044f, 0.0177003983f, 0.0188018531f, 0.0199361145f,
|
||||||
|
0.0211031344f, 0.0223028567f, 0.0235352255f, 0.0248001851f, 0.0260976739f,
|
||||||
|
0.0274276342f, 0.0287899990f, 0.0301847085f, 0.0316116922f, 0.0330708846f,
|
||||||
|
0.0345622115f, 0.0360856056f, 0.0376409888f, 0.0392282903f, 0.0408474281f,
|
||||||
|
0.0424983241f, 0.0441808924f, 0.0458950549f, 0.0476407260f, 0.0494178124f,
|
||||||
|
0.0512262285f, 0.0530658774f, 0.0549366735f, 0.0568385124f, 0.0587713011f,
|
||||||
|
0.0607349351f, 0.0627293140f, 0.0647543296f, 0.0668098852f, 0.0688958541f,
|
||||||
|
0.0710121393f, 0.0731586292f, 0.0753351897f, 0.0775417164f, 0.0797780901f,
|
||||||
|
0.0820441842f, 0.0843398646f, 0.0866650119f, 0.0890194997f, 0.0914031938f,
|
||||||
|
0.0938159525f, 0.0962576419f, 0.0987281203f, 0.101227246f, 0.103754878f,
|
||||||
|
0.106310867f, 0.108895063f, 0.111507311f, 0.114147455f, 0.116815343f,
|
||||||
|
0.119510807f, 0.122233689f, 0.124983832f, 0.127761051f, 0.130565181f,
|
||||||
|
0.133396059f, 0.136253506f, 0.139137328f, 0.142047361f, 0.144983411f,
|
||||||
|
0.147945285f, 0.150932819f, 0.153945804f, 0.156984031f, 0.160047337f,
|
||||||
|
0.163135484f, 0.166248307f, 0.169385567f, 0.172547072f, 0.175732598f,
|
||||||
|
0.178941950f, 0.182174906f, 0.185431242f, 0.188710734f, 0.192013159f,
|
||||||
|
0.195338294f, 0.198685899f, 0.202055752f, 0.205447599f, 0.208861232f,
|
||||||
|
0.212296382f, 0.215752810f, 0.219230279f, 0.222728521f, 0.226247311f,
|
||||||
|
0.229786381f, 0.233345464f, 0.236924306f, 0.240522653f, 0.244140238f,
|
||||||
|
0.247776777f, 0.251432031f, 0.255105674f, 0.258797467f, 0.262507141f,
|
||||||
|
0.266234398f, 0.269978970f, 0.273740560f, 0.277518868f, 0.281313598f,
|
||||||
|
0.285124481f, 0.288951218f, 0.292793512f, 0.296651065f, 0.300523549f,
|
||||||
|
0.304410696f, 0.308312178f, 0.312227666f, 0.316156894f, 0.320099503f,
|
||||||
|
0.324055225f, 0.328023702f, 0.332004637f, 0.335997701f, 0.340002567f,
|
||||||
|
0.344018906f, 0.348046392f, 0.352084726f, 0.356133521f, 0.360192508f,
|
||||||
|
0.364261299f, 0.368339598f, 0.372427016f, 0.376523286f, 0.380627990f,
|
||||||
|
0.384740859f, 0.388861477f, 0.392989576f, 0.397124738f, 0.401266664f,
|
||||||
|
0.405414969f, 0.409569323f, 0.413729399f, 0.417894781f, 0.422065198f,
|
||||||
|
0.426240236f, 0.430419534f, 0.434602767f, 0.438789606f, 0.442979604f,
|
||||||
|
0.447172493f, 0.451367885f, 0.455565393f, 0.459764689f, 0.463965416f,
|
||||||
|
0.468167186f, 0.472369671f, 0.476572484f, 0.480775267f, 0.484977663f,
|
||||||
|
0.489179343f, 0.493379891f, 0.497579008f, 0.501776278f, 0.505971372f,
|
||||||
|
0.510163903f, 0.514353573f, 0.518539906f, 0.522722721f, 0.526901484f,
|
||||||
|
0.531075954f, 0.535245717f, 0.539410412f, 0.543569744f, 0.547723293f,
|
||||||
|
0.551870763f, 0.556011736f, 0.560145974f, 0.564273000f, 0.568392515f,
|
||||||
|
0.572504222f, 0.576607704f, 0.580702662f, 0.584788740f, 0.588865638f,
|
||||||
|
0.592932940f, 0.596990347f, 0.601037502f, 0.605074167f, 0.609099925f,
|
||||||
|
0.613114417f, 0.617117405f, 0.621108532f, 0.625087440f, 0.629053831f,
|
||||||
|
0.633007407f, 0.636947870f, 0.640874863f, 0.644788086f, 0.648687243f,
|
||||||
|
0.652572036f, 0.656442165f, 0.660297334f, 0.664137185f, 0.667961538f,
|
||||||
|
0.671769977f, 0.675562322f, 0.679338276f, 0.683097482f, 0.686839759f,
|
||||||
|
0.690564752f, 0.694272280f, 0.697961986f, 0.701633692f, 0.705287039f,
|
||||||
|
0.708921850f, 0.712537885f, 0.716134787f, 0.719712436f, 0.723270535f,
|
||||||
|
0.726808906f, 0.730327189f, 0.733825266f, 0.737302899f, 0.740759790f,
|
||||||
|
0.744195819f, 0.747610688f, 0.751004279f, 0.754376352f, 0.757726669f,
|
||||||
|
0.761055112f, 0.764361382f, 0.767645359f, 0.770906866f, 0.774145722f,
|
||||||
|
0.777361751f, 0.780554771f, 0.783724606f, 0.786871076f, 0.789994121f,
|
||||||
|
0.793093503f, 0.796169102f, 0.799220800f, 0.802248418f, 0.805251837f,
|
||||||
|
0.808230937f, 0.811185598f, 0.814115703f, 0.817021132f, 0.819901764f,
|
||||||
|
0.822757542f, 0.825588286f, 0.828393936f, 0.831174433f, 0.833929658f,
|
||||||
|
0.836659551f, 0.839363992f, 0.842042983f, 0.844696403f, 0.847324252f,
|
||||||
|
0.849926353f, 0.852502763f, 0.855053425f, 0.857578218f, 0.860077202f,
|
||||||
|
0.862550259f, 0.864997447f, 0.867418647f, 0.869813919f, 0.872183204f,
|
||||||
|
0.874526560f, 0.876843870f, 0.879135191f, 0.881400526f, 0.883639932f,
|
||||||
|
0.885853291f, 0.888040781f, 0.890202343f, 0.892337978f, 0.894447744f,
|
||||||
|
0.896531701f, 0.898589849f, 0.900622249f, 0.902628958f, 0.904610038f,
|
||||||
|
0.906565487f, 0.908495426f, 0.910399914f, 0.912279010f, 0.914132774f,
|
||||||
|
0.915961266f, 0.917764664f, 0.919542909f, 0.921296239f, 0.923024654f,
|
||||||
|
0.924728215f, 0.926407158f, 0.928061485f, 0.929691315f, 0.931296766f,
|
||||||
|
0.932878017f, 0.934435070f, 0.935968161f, 0.937477291f, 0.938962698f,
|
||||||
|
0.940424502f, 0.941862822f, 0.943277776f, 0.944669485f, 0.946038187f,
|
||||||
|
0.947383940f, 0.948706925f, 0.950007319f, 0.951285243f, 0.952540874f,
|
||||||
|
0.953774393f, 0.954985917f, 0.956175685f, 0.957343817f, 0.958490491f,
|
||||||
|
0.959615886f, 0.960720181f, 0.961803555f, 0.962866247f, 0.963908315f,
|
||||||
|
0.964930058f, 0.965931594f, 0.966913164f, 0.967874944f, 0.968817174f,
|
||||||
|
0.969739914f, 0.970643520f, 0.971528113f, 0.972393870f, 0.973241091f,
|
||||||
|
0.974069893f, 0.974880517f, 0.975673139f, 0.976447999f, 0.977205336f,
|
||||||
|
0.977945268f, 0.978668094f, 0.979374051f, 0.980063200f, 0.980735898f,
|
||||||
|
0.981392324f, 0.982032716f, 0.982657254f, 0.983266115f, 0.983859658f,
|
||||||
|
0.984437943f, 0.985001266f, 0.985549867f, 0.986083925f, 0.986603677f,
|
||||||
|
0.987109363f, 0.987601161f, 0.988079309f, 0.988544047f, 0.988995552f,
|
||||||
|
0.989434063f, 0.989859879f, 0.990273118f, 0.990674019f, 0.991062820f,
|
||||||
|
0.991439700f, 0.991804957f, 0.992158771f, 0.992501318f, 0.992832899f,
|
||||||
|
0.993153632f, 0.993463814f, 0.993763626f, 0.994053245f, 0.994332969f,
|
||||||
|
0.994602919f, 0.994863331f, 0.995114446f, 0.995356441f, 0.995589554f,
|
||||||
|
0.995813966f, 0.996029854f, 0.996237516f, 0.996437073f, 0.996628702f,
|
||||||
|
0.996812642f, 0.996989131f, 0.997158289f, 0.997320294f, 0.997475445f,
|
||||||
|
0.997623861f, 0.997765720f, 0.997901261f, 0.998030603f, 0.998153925f,
|
||||||
|
0.998271465f, 0.998383403f, 0.998489857f, 0.998591006f, 0.998687088f,
|
||||||
|
0.998778164f, 0.998864532f, 0.998946249f, 0.999023557f, 0.999096513f,
|
||||||
|
0.999165416f, 0.999230266f, 0.999291301f, 0.999348700f, 0.999402523f,
|
||||||
|
0.999453008f, 0.999500215f, 0.999544322f, 0.999585509f, 0.999623775f,
|
||||||
|
0.999659419f, 0.999692440f, 0.999723017f, 0.999751270f, 0.999777317f,
|
||||||
|
0.999801278f, 0.999823213f, 0.999843359f, 0.999861658f, 0.999878347f,
|
||||||
|
0.999893486f, 0.999907196f, 0.999919534f, 0.999930561f, 0.999940455f,
|
||||||
|
0.999949217f, 0.999957025f, 0.999963880f, 0.999969840f, 0.999975085f,
|
||||||
|
0.999979615f, 0.999983490f, 0.999986768f, 0.999989510f, 0.999991834f,
|
||||||
|
0.999993742f, 0.999995291f, 0.999996543f, 0.999997556f, 0.999998271f,
|
||||||
|
0.999998868f, 0.999999285f, 0.999999523f, 0.999999762f, 0.999999881f,
|
||||||
|
0.999999940f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
|
||||||
|
};
|
||||||
|
|
||||||
|
const float rnn_dct_table[] = {
|
||||||
|
0.707106769f, 0.998795450f, 0.995184720f, 0.989176512f, 0.980785251f,
|
||||||
|
0.970031261f, 0.956940353f, 0.941544056f, 0.923879504f, 0.903989315f,
|
||||||
|
0.881921291f, 0.857728601f, 0.831469595f, 0.803207517f, 0.773010433f,
|
||||||
|
0.740951121f, 0.707106769f, 0.671558976f, 0.634393275f, 0.595699310f,
|
||||||
|
0.555570245f, 0.514102757f, 0.471396744f, 0.427555084f, 0.382683426f,
|
||||||
|
0.336889863f, 0.290284663f, 0.242980182f, 0.195090324f, 0.146730468f,
|
||||||
|
0.0980171412f, 0.0490676761f, 0.707106769f, 0.989176512f, 0.956940353f,
|
||||||
|
0.903989315f, 0.831469595f, 0.740951121f, 0.634393275f, 0.514102757f,
|
||||||
|
0.382683426f, 0.242980182f, 0.0980171412f, -0.0490676761f, -0.195090324f,
|
||||||
|
-0.336889863f, -0.471396744f, -0.595699310f, -0.707106769f, -0.803207517f,
|
||||||
|
-0.881921291f, -0.941544056f, -0.980785251f, -0.998795450f, -0.995184720f,
|
||||||
|
-0.970031261f, -0.923879504f, -0.857728601f, -0.773010433f, -0.671558976f,
|
||||||
|
-0.555570245f, -0.427555084f, -0.290284663f, -0.146730468f, 0.707106769f,
|
||||||
|
0.970031261f, 0.881921291f, 0.740951121f, 0.555570245f, 0.336889863f,
|
||||||
|
0.0980171412f, -0.146730468f, -0.382683426f, -0.595699310f, -0.773010433f,
|
||||||
|
-0.903989315f, -0.980785251f, -0.998795450f, -0.956940353f, -0.857728601f,
|
||||||
|
-0.707106769f, -0.514102757f, -0.290284663f, -0.0490676761f, 0.195090324f,
|
||||||
|
0.427555084f, 0.634393275f, 0.803207517f, 0.923879504f, 0.989176512f,
|
||||||
|
0.995184720f, 0.941544056f, 0.831469595f, 0.671558976f, 0.471396744f,
|
||||||
|
0.242980182f, 0.707106769f, 0.941544056f, 0.773010433f, 0.514102757f,
|
||||||
|
0.195090324f, -0.146730468f, -0.471396744f, -0.740951121f, -0.923879504f,
|
||||||
|
-0.998795450f, -0.956940353f, -0.803207517f, -0.555570245f, -0.242980182f,
|
||||||
|
0.0980171412f, 0.427555084f, 0.707106769f, 0.903989315f, 0.995184720f,
|
||||||
|
0.970031261f, 0.831469595f, 0.595699310f, 0.290284663f, -0.0490676761f,
|
||||||
|
-0.382683426f, -0.671558976f, -0.881921291f, -0.989176512f, -0.980785251f,
|
||||||
|
-0.857728601f, -0.634393275f, -0.336889863f, 0.707106769f, 0.903989315f,
|
||||||
|
0.634393275f, 0.242980182f, -0.195090324f, -0.595699310f, -0.881921291f,
|
||||||
|
-0.998795450f, -0.923879504f, -0.671558976f, -0.290284663f, 0.146730468f,
|
||||||
|
0.555570245f, 0.857728601f, 0.995184720f, 0.941544056f, 0.707106769f,
|
||||||
|
0.336889863f, -0.0980171412f, -0.514102757f, -0.831469595f, -0.989176512f,
|
||||||
|
-0.956940353f, -0.740951121f, -0.382683426f, 0.0490676761f, 0.471396744f,
|
||||||
|
0.803207517f, 0.980785251f, 0.970031261f, 0.773010433f, 0.427555084f,
|
||||||
|
0.707106769f, 0.857728601f, 0.471396744f, -0.0490676761f, -0.555570245f,
|
||||||
|
-0.903989315f, -0.995184720f, -0.803207517f, -0.382683426f, 0.146730468f,
|
||||||
|
0.634393275f, 0.941544056f, 0.980785251f, 0.740951121f, 0.290284663f,
|
||||||
|
-0.242980182f, -0.707106769f, -0.970031261f, -0.956940353f, -0.671558976f,
|
||||||
|
-0.195090324f, 0.336889863f, 0.773010433f, 0.989176512f, 0.923879504f,
|
||||||
|
0.595699310f, 0.0980171412f, -0.427555084f, -0.831469595f, -0.998795450f,
|
||||||
|
-0.881921291f, -0.514102757f, 0.707106769f, 0.803207517f, 0.290284663f,
|
||||||
|
-0.336889863f, -0.831469595f, -0.998795450f, -0.773010433f, -0.242980182f,
|
||||||
|
0.382683426f, 0.857728601f, 0.995184720f, 0.740951121f, 0.195090324f,
|
||||||
|
-0.427555084f, -0.881921291f, -0.989176512f, -0.707106769f, -0.146730468f,
|
||||||
|
0.471396744f, 0.903989315f, 0.980785251f, 0.671558976f, 0.0980171412f,
|
||||||
|
-0.514102757f, -0.923879504f, -0.970031261f, -0.634393275f, -0.0490676761f,
|
||||||
|
0.555570245f, 0.941544056f, 0.956940353f, 0.595699310f, 0.707106769f,
|
||||||
|
0.740951121f, 0.0980171412f, -0.595699310f, -0.980785251f, -0.857728601f,
|
||||||
|
-0.290284663f, 0.427555084f, 0.923879504f, 0.941544056f, 0.471396744f,
|
||||||
|
-0.242980182f, -0.831469595f, -0.989176512f, -0.634393275f, 0.0490676761f,
|
||||||
|
0.707106769f, 0.998795450f, 0.773010433f, 0.146730468f, -0.555570245f,
|
||||||
|
-0.970031261f, -0.881921291f, -0.336889863f, 0.382683426f, 0.903989315f,
|
||||||
|
0.956940353f, 0.514102757f, -0.195090324f, -0.803207517f, -0.995184720f,
|
||||||
|
-0.671558976f, 0.707106769f, 0.671558976f, -0.0980171412f, -0.803207517f,
|
||||||
|
-0.980785251f, -0.514102757f, 0.290284663f, 0.903989315f, 0.923879504f,
|
||||||
|
0.336889863f, -0.471396744f, -0.970031261f, -0.831469595f, -0.146730468f,
|
||||||
|
0.634393275f, 0.998795450f, 0.707106769f, -0.0490676761f, -0.773010433f,
|
||||||
|
-0.989176512f, -0.555570245f, 0.242980182f, 0.881921291f, 0.941544056f,
|
||||||
|
0.382683426f, -0.427555084f, -0.956940353f, -0.857728601f, -0.195090324f,
|
||||||
|
0.595699310f, 0.995184720f, 0.740951121f, 0.707106769f, 0.595699310f,
|
||||||
|
-0.290284663f, -0.941544056f, -0.831469595f, -0.0490676761f, 0.773010433f,
|
||||||
|
0.970031261f, 0.382683426f, -0.514102757f, -0.995184720f, -0.671558976f,
|
||||||
|
0.195090324f, 0.903989315f, 0.881921291f, 0.146730468f, -0.707106769f,
|
||||||
|
-0.989176512f, -0.471396744f, 0.427555084f, 0.980785251f, 0.740951121f,
|
||||||
|
-0.0980171412f, -0.857728601f, -0.923879504f, -0.242980182f, 0.634393275f,
|
||||||
|
0.998795450f, 0.555570245f, -0.336889863f, -0.956940353f, -0.803207517f,
|
||||||
|
0.707106769f, 0.514102757f, -0.471396744f, -0.998795450f, -0.555570245f,
|
||||||
|
0.427555084f, 0.995184720f, 0.595699310f, -0.382683426f, -0.989176512f,
|
||||||
|
-0.634393275f, 0.336889863f, 0.980785251f, 0.671558976f, -0.290284663f,
|
||||||
|
-0.970031261f, -0.707106769f, 0.242980182f, 0.956940353f, 0.740951121f,
|
||||||
|
-0.195090324f, -0.941544056f, -0.773010433f, 0.146730468f, 0.923879504f,
|
||||||
|
0.803207517f, -0.0980171412f, -0.903989315f, -0.831469595f, 0.0490676761f,
|
||||||
|
0.881921291f, 0.857728601f, 0.707106769f, 0.427555084f, -0.634393275f,
|
||||||
|
-0.970031261f, -0.195090324f, 0.803207517f, 0.881921291f, -0.0490676761f,
|
||||||
|
-0.923879504f, -0.740951121f, 0.290284663f, 0.989176512f, 0.555570245f,
|
||||||
|
-0.514102757f, -0.995184720f, -0.336889863f, 0.707106769f, 0.941544056f,
|
||||||
|
0.0980171412f, -0.857728601f, -0.831469595f, 0.146730468f, 0.956940353f,
|
||||||
|
0.671558976f, -0.382683426f, -0.998795450f, -0.471396744f, 0.595699310f,
|
||||||
|
0.980785251f, 0.242980182f, -0.773010433f, -0.903989315f, 0.707106769f,
|
||||||
|
0.336889863f, -0.773010433f, -0.857728601f, 0.195090324f, 0.989176512f,
|
||||||
|
0.471396744f, -0.671558976f, -0.923879504f, 0.0490676761f, 0.956940353f,
|
||||||
|
0.595699310f, -0.555570245f, -0.970031261f, -0.0980171412f, 0.903989315f,
|
||||||
|
0.707106769f, -0.427555084f, -0.995184720f, -0.242980182f, 0.831469595f,
|
||||||
|
0.803207517f, -0.290284663f, -0.998795450f, -0.382683426f, 0.740951121f,
|
||||||
|
0.881921291f, -0.146730468f, -0.980785251f, -0.514102757f, 0.634393275f,
|
||||||
|
0.941544056f, 0.707106769f, 0.242980182f, -0.881921291f, -0.671558976f,
|
||||||
|
0.555570245f, 0.941544056f, -0.0980171412f, -0.989176512f, -0.382683426f,
|
||||||
|
0.803207517f, 0.773010433f, -0.427555084f, -0.980785251f, -0.0490676761f,
|
||||||
|
0.956940353f, 0.514102757f, -0.707106769f, -0.857728601f, 0.290284663f,
|
||||||
|
0.998795450f, 0.195090324f, -0.903989315f, -0.634393275f, 0.595699310f,
|
||||||
|
0.923879504f, -0.146730468f, -0.995184720f, -0.336889863f, 0.831469595f,
|
||||||
|
0.740951121f, -0.471396744f, -0.970031261f, 0.707106769f, 0.146730468f,
|
||||||
|
-0.956940353f, -0.427555084f, 0.831469595f, 0.671558976f, -0.634393275f,
|
||||||
|
-0.857728601f, 0.382683426f, 0.970031261f, -0.0980171412f, -0.998795450f,
|
||||||
|
-0.195090324f, 0.941544056f, 0.471396744f, -0.803207517f, -0.707106769f,
|
||||||
|
0.595699310f, 0.881921291f, -0.336889863f, -0.980785251f, 0.0490676761f,
|
||||||
|
0.995184720f, 0.242980182f, -0.923879504f, -0.514102757f, 0.773010433f,
|
||||||
|
0.740951121f, -0.555570245f, -0.903989315f, 0.290284663f, 0.989176512f,
|
||||||
|
0.707106769f, 0.0490676761f, -0.995184720f, -0.146730468f, 0.980785251f,
|
||||||
|
0.242980182f, -0.956940353f, -0.336889863f, 0.923879504f, 0.427555084f,
|
||||||
|
-0.881921291f, -0.514102757f, 0.831469595f, 0.595699310f, -0.773010433f,
|
||||||
|
-0.671558976f, 0.707106769f, 0.740951121f, -0.634393275f, -0.803207517f,
|
||||||
|
0.555570245f, 0.857728601f, -0.471396744f, -0.903989315f, 0.382683426f,
|
||||||
|
0.941544056f, -0.290284663f, -0.970031261f, 0.195090324f, 0.989176512f,
|
||||||
|
-0.0980171412f, -0.998795450f, 0.707106769f, -0.0490676761f, -0.995184720f,
|
||||||
|
0.146730468f, 0.980785251f, -0.242980182f, -0.956940353f, 0.336889863f,
|
||||||
|
0.923879504f, -0.427555084f, -0.881921291f, 0.514102757f, 0.831469595f,
|
||||||
|
-0.595699310f, -0.773010433f, 0.671558976f, 0.707106769f, -0.740951121f,
|
||||||
|
-0.634393275f, 0.803207517f, 0.555570245f, -0.857728601f, -0.471396744f,
|
||||||
|
0.903989315f, 0.382683426f, -0.941544056f, -0.290284663f, 0.970031261f,
|
||||||
|
0.195090324f, -0.989176512f, -0.0980171412f, 0.998795450f, 0.707106769f,
|
||||||
|
-0.146730468f, -0.956940353f, 0.427555084f, 0.831469595f, -0.671558976f,
|
||||||
|
-0.634393275f, 0.857728601f, 0.382683426f, -0.970031261f, -0.0980171412f,
|
||||||
|
0.998795450f, -0.195090324f, -0.941544056f, 0.471396744f, 0.803207517f,
|
||||||
|
-0.707106769f, -0.595699310f, 0.881921291f, 0.336889863f, -0.980785251f,
|
||||||
|
-0.0490676761f, 0.995184720f, -0.242980182f, -0.923879504f, 0.514102757f,
|
||||||
|
0.773010433f, -0.740951121f, -0.555570245f, 0.903989315f, 0.290284663f,
|
||||||
|
-0.989176512f, 0.707106769f, -0.242980182f, -0.881921291f, 0.671558976f,
|
||||||
|
0.555570245f, -0.941544056f, -0.0980171412f, 0.989176512f, -0.382683426f,
|
||||||
|
-0.803207517f, 0.773010433f, 0.427555084f, -0.980785251f, 0.0490676761f,
|
||||||
|
0.956940353f, -0.514102757f, -0.707106769f, 0.857728601f, 0.290284663f,
|
||||||
|
-0.998795450f, 0.195090324f, 0.903989315f, -0.634393275f, -0.595699310f,
|
||||||
|
0.923879504f, 0.146730468f, -0.995184720f, 0.336889863f, 0.831469595f,
|
||||||
|
-0.740951121f, -0.471396744f, 0.970031261f, 0.707106769f, -0.336889863f,
|
||||||
|
-0.773010433f, 0.857728601f, 0.195090324f, -0.989176512f, 0.471396744f,
|
||||||
|
0.671558976f, -0.923879504f, -0.0490676761f, 0.956940353f, -0.595699310f,
|
||||||
|
-0.555570245f, 0.970031261f, -0.0980171412f, -0.903989315f, 0.707106769f,
|
||||||
|
0.427555084f, -0.995184720f, 0.242980182f, 0.831469595f, -0.803207517f,
|
||||||
|
-0.290284663f, 0.998795450f, -0.382683426f, -0.740951121f, 0.881921291f,
|
||||||
|
0.146730468f, -0.980785251f, 0.514102757f, 0.634393275f, -0.941544056f,
|
||||||
|
0.707106769f, -0.427555084f, -0.634393275f, 0.970031261f, -0.195090324f,
|
||||||
|
-0.803207517f, 0.881921291f, 0.0490676761f, -0.923879504f, 0.740951121f,
|
||||||
|
0.290284663f, -0.989176512f, 0.555570245f, 0.514102757f, -0.995184720f,
|
||||||
|
0.336889863f, 0.707106769f, -0.941544056f, 0.0980171412f, 0.857728601f,
|
||||||
|
-0.831469595f, -0.146730468f, 0.956940353f, -0.671558976f, -0.382683426f,
|
||||||
|
0.998795450f, -0.471396744f, -0.595699310f, 0.980785251f, -0.242980182f,
|
||||||
|
-0.773010433f, 0.903989315f, 0.707106769f, -0.514102757f, -0.471396744f,
|
||||||
|
0.998795450f, -0.555570245f, -0.427555084f, 0.995184720f, -0.595699310f,
|
||||||
|
-0.382683426f, 0.989176512f, -0.634393275f, -0.336889863f, 0.980785251f,
|
||||||
|
-0.671558976f, -0.290284663f, 0.970031261f, -0.707106769f, -0.242980182f,
|
||||||
|
0.956940353f, -0.740951121f, -0.195090324f, 0.941544056f, -0.773010433f,
|
||||||
|
-0.146730468f, 0.923879504f, -0.803207517f, -0.0980171412f, 0.903989315f,
|
||||||
|
-0.831469595f, -0.0490676761f, 0.881921291f, -0.857728601f, 0.707106769f,
|
||||||
|
-0.595699310f, -0.290284663f, 0.941544056f, -0.831469595f, 0.0490676761f,
|
||||||
|
0.773010433f, -0.970031261f, 0.382683426f, 0.514102757f, -0.995184720f,
|
||||||
|
0.671558976f, 0.195090324f, -0.903989315f, 0.881921291f, -0.146730468f,
|
||||||
|
-0.707106769f, 0.989176512f, -0.471396744f, -0.427555084f, 0.980785251f,
|
||||||
|
-0.740951121f, -0.0980171412f, 0.857728601f, -0.923879504f, 0.242980182f,
|
||||||
|
0.634393275f, -0.998795450f, 0.555570245f, 0.336889863f, -0.956940353f,
|
||||||
|
0.803207517f, 0.707106769f, -0.671558976f, -0.0980171412f, 0.803207517f,
|
||||||
|
-0.980785251f, 0.514102757f, 0.290284663f, -0.903989315f, 0.923879504f,
|
||||||
|
-0.336889863f, -0.471396744f, 0.970031261f, -0.831469595f, 0.146730468f,
|
||||||
|
0.634393275f, -0.998795450f, 0.707106769f, 0.0490676761f, -0.773010433f,
|
||||||
|
0.989176512f, -0.555570245f, -0.242980182f, 0.881921291f, -0.941544056f,
|
||||||
|
0.382683426f, 0.427555084f, -0.956940353f, 0.857728601f, -0.195090324f,
|
||||||
|
-0.595699310f, 0.995184720f, -0.740951121f, 0.707106769f, -0.740951121f,
|
||||||
|
0.0980171412f, 0.595699310f, -0.980785251f, 0.857728601f, -0.290284663f,
|
||||||
|
-0.427555084f, 0.923879504f, -0.941544056f, 0.471396744f, 0.242980182f,
|
||||||
|
-0.831469595f, 0.989176512f, -0.634393275f, -0.0490676761f, 0.707106769f,
|
||||||
|
-0.998795450f, 0.773010433f, -0.146730468f, -0.555570245f, 0.970031261f,
|
||||||
|
-0.881921291f, 0.336889863f, 0.382683426f, -0.903989315f, 0.956940353f,
|
||||||
|
-0.514102757f, -0.195090324f, 0.803207517f, -0.995184720f, 0.671558976f,
|
||||||
|
0.707106769f, -0.803207517f, 0.290284663f, 0.336889863f, -0.831469595f,
|
||||||
|
0.998795450f, -0.773010433f, 0.242980182f, 0.382683426f, -0.857728601f,
|
||||||
|
0.995184720f, -0.740951121f, 0.195090324f, 0.427555084f, -0.881921291f,
|
||||||
|
0.989176512f, -0.707106769f, 0.146730468f, 0.471396744f, -0.903989315f,
|
||||||
|
0.980785251f, -0.671558976f, 0.0980171412f, 0.514102757f, -0.923879504f,
|
||||||
|
0.970031261f, -0.634393275f, 0.0490676761f, 0.555570245f, -0.941544056f,
|
||||||
|
0.956940353f, -0.595699310f, 0.707106769f, -0.857728601f, 0.471396744f,
|
||||||
|
0.0490676761f, -0.555570245f, 0.903989315f, -0.995184720f, 0.803207517f,
|
||||||
|
-0.382683426f, -0.146730468f, 0.634393275f, -0.941544056f, 0.980785251f,
|
||||||
|
-0.740951121f, 0.290284663f, 0.242980182f, -0.707106769f, 0.970031261f,
|
||||||
|
-0.956940353f, 0.671558976f, -0.195090324f, -0.336889863f, 0.773010433f,
|
||||||
|
-0.989176512f, 0.923879504f, -0.595699310f, 0.0980171412f, 0.427555084f,
|
||||||
|
-0.831469595f, 0.998795450f, -0.881921291f, 0.514102757f, 0.707106769f,
|
||||||
|
-0.903989315f, 0.634393275f, -0.242980182f, -0.195090324f, 0.595699310f,
|
||||||
|
-0.881921291f, 0.998795450f, -0.923879504f, 0.671558976f, -0.290284663f,
|
||||||
|
-0.146730468f, 0.555570245f, -0.857728601f, 0.995184720f, -0.941544056f,
|
||||||
|
0.707106769f, -0.336889863f, -0.0980171412f, 0.514102757f, -0.831469595f,
|
||||||
|
0.989176512f, -0.956940353f, 0.740951121f, -0.382683426f, -0.0490676761f,
|
||||||
|
0.471396744f, -0.803207517f, 0.980785251f, -0.970031261f, 0.773010433f,
|
||||||
|
-0.427555084f, 0.707106769f, -0.941544056f, 0.773010433f, -0.514102757f,
|
||||||
|
0.195090324f, 0.146730468f, -0.471396744f, 0.740951121f, -0.923879504f,
|
||||||
|
0.998795450f, -0.956940353f, 0.803207517f, -0.555570245f, 0.242980182f,
|
||||||
|
0.0980171412f, -0.427555084f, 0.707106769f, -0.903989315f, 0.995184720f,
|
||||||
|
-0.970031261f, 0.831469595f, -0.595699310f, 0.290284663f, 0.0490676761f,
|
||||||
|
-0.382683426f, 0.671558976f, -0.881921291f, 0.989176512f, -0.980785251f,
|
||||||
|
0.857728601f, -0.634393275f, 0.336889863f, 0.707106769f, -0.970031261f,
|
||||||
|
0.881921291f, -0.740951121f, 0.555570245f, -0.336889863f, 0.0980171412f,
|
||||||
|
0.146730468f, -0.382683426f, 0.595699310f, -0.773010433f, 0.903989315f,
|
||||||
|
-0.980785251f, 0.998795450f, -0.956940353f, 0.857728601f, -0.707106769f,
|
||||||
|
0.514102757f, -0.290284663f, 0.0490676761f, 0.195090324f, -0.427555084f,
|
||||||
|
0.634393275f, -0.803207517f, 0.923879504f, -0.989176512f, 0.995184720f,
|
||||||
|
-0.941544056f, 0.831469595f, -0.671558976f, 0.471396744f, -0.242980182f,
|
||||||
|
0.707106769f, -0.989176512f, 0.956940353f, -0.903989315f, 0.831469595f,
|
||||||
|
-0.740951121f, 0.634393275f, -0.514102757f, 0.382683426f, -0.242980182f,
|
||||||
|
0.0980171412f, 0.0490676761f, -0.195090324f, 0.336889863f, -0.471396744f,
|
||||||
|
0.595699310f, -0.707106769f, 0.803207517f, -0.881921291f, 0.941544056f,
|
||||||
|
-0.980785251f, 0.998795450f, -0.995184720f, 0.970031261f, -0.923879504f,
|
||||||
|
0.857728601f, -0.773010433f, 0.671558976f, -0.555570245f, 0.427555084f,
|
||||||
|
-0.290284663f, 0.146730468f, 0.707106769f, -0.998795450f, 0.995184720f,
|
||||||
|
-0.989176512f, 0.980785251f, -0.970031261f, 0.956940353f, -0.941544056f,
|
||||||
|
0.923879504f, -0.903989315f, 0.881921291f, -0.857728601f, 0.831469595f,
|
||||||
|
-0.803207517f, 0.773010433f, -0.740951121f, 0.707106769f, -0.671558976f,
|
||||||
|
0.634393275f, -0.595699310f, 0.555570245f, -0.514102757f, 0.471396744f,
|
||||||
|
-0.427555084f, 0.382683426f, -0.336889863f, 0.290284663f, -0.242980182f,
|
||||||
|
0.195090324f, -0.146730468f, 0.0980171412f, -0.0490676761f, };
|
||||||
388
third_party/rnnoise/src/vec.h
vendored
Normal file
388
third_party/rnnoise/src/vec.h
vendored
Normal file
@@ -0,0 +1,388 @@
|
|||||||
|
/* Copyright (c) 2018 Mozilla
|
||||||
|
2008-2011 Octasic Inc.
|
||||||
|
2012-2017 Jean-Marc Valin */
|
||||||
|
/*
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
- Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||||||
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef VEC_H
|
||||||
|
#define VEC_H
|
||||||
|
|
||||||
|
#include "opus_types.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include <math.h>
|
||||||
|
#include "arch.h"
|
||||||
|
#include "x86/x86_arch_macros.h"
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__AVX__) || defined(__SSE2__)
|
||||||
|
#include "vec_avx.h"
|
||||||
|
#elif (defined(__ARM_NEON__) || defined(__ARM_NEON)) && !defined(DISABLE_NEON)
|
||||||
|
#include "vec_neon.h"
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define MAX_INPUTS (2048)
|
||||||
|
|
||||||
|
#define NO_OPTIMIZATIONS
|
||||||
|
|
||||||
|
static inline void sgemv16x1(float *out, const float *weights, int rows, int cols, int col_stride, const float *x)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
RNN_CLEAR(out, rows);
|
||||||
|
for (i=0;i<rows;i+=16)
|
||||||
|
{
|
||||||
|
for (j=0;j<cols;j++)
|
||||||
|
{
|
||||||
|
const float * restrict w;
|
||||||
|
float * restrict y;
|
||||||
|
float xj;
|
||||||
|
w = &weights[j*col_stride + i];
|
||||||
|
xj = x[j];
|
||||||
|
y = &out[i];
|
||||||
|
y[0] += w[0]*xj;
|
||||||
|
y[1] += w[1]*xj;
|
||||||
|
y[2] += w[2]*xj;
|
||||||
|
y[3] += w[3]*xj;
|
||||||
|
y[4] += w[4]*xj;
|
||||||
|
y[5] += w[5]*xj;
|
||||||
|
y[6] += w[6]*xj;
|
||||||
|
y[7] += w[7]*xj;
|
||||||
|
y[8] += w[8]*xj;
|
||||||
|
y[9] += w[9]*xj;
|
||||||
|
y[10] += w[10]*xj;
|
||||||
|
y[11] += w[11]*xj;
|
||||||
|
y[12] += w[12]*xj;
|
||||||
|
y[13] += w[13]*xj;
|
||||||
|
y[14] += w[14]*xj;
|
||||||
|
y[15] += w[15]*xj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void sgemv8x1(float *out, const float *weights, int rows, int cols, int col_stride, const float *x)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
RNN_CLEAR(out, rows);
|
||||||
|
for (i=0;i<rows;i+=8)
|
||||||
|
{
|
||||||
|
for (j=0;j<cols;j++)
|
||||||
|
{
|
||||||
|
const float * restrict w;
|
||||||
|
float * restrict y;
|
||||||
|
float xj;
|
||||||
|
w = &weights[j*col_stride + i];
|
||||||
|
xj = x[j];
|
||||||
|
y = &out[i];
|
||||||
|
y[0] += w[0]*xj;
|
||||||
|
y[1] += w[1]*xj;
|
||||||
|
y[2] += w[2]*xj;
|
||||||
|
y[3] += w[3]*xj;
|
||||||
|
y[4] += w[4]*xj;
|
||||||
|
y[5] += w[5]*xj;
|
||||||
|
y[6] += w[6]*xj;
|
||||||
|
y[7] += w[7]*xj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void sgemv(float *out, const float *weights, int rows, int cols, int col_stride, const float *x)
|
||||||
|
{
|
||||||
|
if ((rows&0xf) == 0) sgemv16x1(out, weights, rows, cols, col_stride, x);
|
||||||
|
else if ((rows&0x7) == 0) sgemv8x1(out, weights, rows, cols, col_stride, x);
|
||||||
|
else {
|
||||||
|
int i, j;
|
||||||
|
for (i=0;i<rows;i++)
|
||||||
|
{
|
||||||
|
out[i] = 0;
|
||||||
|
for (j=0;j<cols;j++) out[i] += weights[j*col_stride + i]*x[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void sparse_sgemv8x4(float *out, const float *w, const int *idx, int rows, const float *x)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
RNN_CLEAR(out, rows);
|
||||||
|
for (i=0;i<rows;i+=8)
|
||||||
|
{
|
||||||
|
int cols;
|
||||||
|
cols = *idx++;
|
||||||
|
for (j=0;j<cols;j++)
|
||||||
|
{
|
||||||
|
int pos;
|
||||||
|
float * restrict y;
|
||||||
|
float xj0, xj1, xj2, xj3;
|
||||||
|
pos = (*idx++);
|
||||||
|
xj0 = x[pos+0];
|
||||||
|
xj1 = x[pos+1];
|
||||||
|
xj2 = x[pos+2];
|
||||||
|
xj3 = x[pos+3];
|
||||||
|
y = &out[i];
|
||||||
|
y[0] += w[0]*xj0;
|
||||||
|
y[1] += w[1]*xj0;
|
||||||
|
y[2] += w[2]*xj0;
|
||||||
|
y[3] += w[3]*xj0;
|
||||||
|
y[4] += w[4]*xj0;
|
||||||
|
y[5] += w[5]*xj0;
|
||||||
|
y[6] += w[6]*xj0;
|
||||||
|
y[7] += w[7]*xj0;
|
||||||
|
|
||||||
|
y[0] += w[8]*xj1;
|
||||||
|
y[1] += w[9]*xj1;
|
||||||
|
y[2] += w[10]*xj1;
|
||||||
|
y[3] += w[11]*xj1;
|
||||||
|
y[4] += w[12]*xj1;
|
||||||
|
y[5] += w[13]*xj1;
|
||||||
|
y[6] += w[14]*xj1;
|
||||||
|
y[7] += w[15]*xj1;
|
||||||
|
|
||||||
|
y[0] += w[16]*xj2;
|
||||||
|
y[1] += w[17]*xj2;
|
||||||
|
y[2] += w[18]*xj2;
|
||||||
|
y[3] += w[19]*xj2;
|
||||||
|
y[4] += w[20]*xj2;
|
||||||
|
y[5] += w[21]*xj2;
|
||||||
|
y[6] += w[22]*xj2;
|
||||||
|
y[7] += w[23]*xj2;
|
||||||
|
|
||||||
|
y[0] += w[24]*xj3;
|
||||||
|
y[1] += w[25]*xj3;
|
||||||
|
y[2] += w[26]*xj3;
|
||||||
|
y[3] += w[27]*xj3;
|
||||||
|
y[4] += w[28]*xj3;
|
||||||
|
y[5] += w[29]*xj3;
|
||||||
|
y[6] += w[30]*xj3;
|
||||||
|
y[7] += w[31]*xj3;
|
||||||
|
w += 32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_SU_BIAS
|
||||||
|
static inline void sparse_cgemv8x4(float *out, const opus_int8 *w, const int *idx, const float *scale, int rows, int cols, const float *_x)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
unsigned char x[MAX_INPUTS];
|
||||||
|
for (i=0;i<rows;i++) out[i] = 0;
|
||||||
|
for (i=0;i<cols;i++) x[i] = 127+floor(.5+127*_x[i]);
|
||||||
|
for (i=0;i<rows;i+=8)
|
||||||
|
{
|
||||||
|
int colblocks;
|
||||||
|
colblocks = *idx++;
|
||||||
|
for (j=0;j<colblocks;j++)
|
||||||
|
{
|
||||||
|
int pos;
|
||||||
|
float * restrict y;
|
||||||
|
int xj0, xj1, xj2, xj3;
|
||||||
|
pos = (*idx++);
|
||||||
|
xj0 = x[pos+0];
|
||||||
|
xj1 = x[pos+1];
|
||||||
|
xj2 = x[pos+2];
|
||||||
|
xj3 = x[pos+3];
|
||||||
|
y = &out[i];
|
||||||
|
y[0] += (w[0]*xj0+w[1]*xj1+w[2]*xj2+w[3]*xj3);
|
||||||
|
y[1] += (w[4]*xj0+w[5]*xj1+w[6]*xj2+w[7]*xj3);
|
||||||
|
y[2] += (w[8]*xj0+w[9]*xj1+w[10]*xj2+w[11]*xj3);
|
||||||
|
y[3] += (w[12]*xj0+w[13]*xj1+w[14]*xj2+w[15]*xj3);
|
||||||
|
y[4] += (w[16]*xj0+w[17]*xj1+w[18]*xj2+w[19]*xj3);
|
||||||
|
y[5] += (w[20]*xj0+w[21]*xj1+w[22]*xj2+w[23]*xj3);
|
||||||
|
y[6] += (w[24]*xj0+w[25]*xj1+w[26]*xj2+w[27]*xj3);
|
||||||
|
y[7] += (w[28]*xj0+w[29]*xj1+w[30]*xj2+w[31]*xj3);
|
||||||
|
w += 32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i=0;i<rows;i++) out[i] *= scale[i];
|
||||||
|
}
|
||||||
|
static inline void cgemv8x4(float *out, const opus_int8 *w, const float *scale, int rows, int cols, const float *_x)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
unsigned char x[MAX_INPUTS];
|
||||||
|
for (i=0;i<rows;i++) out[i] = 0;
|
||||||
|
for (i=0;i<cols;i++) x[i] = 127+(int)floor(.5+127*_x[i]);
|
||||||
|
for (i=0;i<rows;i+=8)
|
||||||
|
{
|
||||||
|
for (j=0;j<cols;j+=4)
|
||||||
|
{
|
||||||
|
float *y;
|
||||||
|
float xj0, xj1, xj2, xj3;
|
||||||
|
xj0 = x[j+0];
|
||||||
|
xj1 = x[j+1];
|
||||||
|
xj2 = x[j+2];
|
||||||
|
xj3 = x[j+3];
|
||||||
|
y = &out[i];
|
||||||
|
y[0] += (w[0]*xj0+w[1]*xj1+w[2]*xj2+w[3]*xj3);
|
||||||
|
y[1] += (w[4]*xj0+w[5]*xj1+w[6]*xj2+w[7]*xj3);
|
||||||
|
y[2] += (w[8]*xj0+w[9]*xj1+w[10]*xj2+w[11]*xj3);
|
||||||
|
y[3] += (w[12]*xj0+w[13]*xj1+w[14]*xj2+w[15]*xj3);
|
||||||
|
y[4] += (w[16]*xj0+w[17]*xj1+w[18]*xj2+w[19]*xj3);
|
||||||
|
y[5] += (w[20]*xj0+w[21]*xj1+w[22]*xj2+w[23]*xj3);
|
||||||
|
y[6] += (w[24]*xj0+w[25]*xj1+w[26]*xj2+w[27]*xj3);
|
||||||
|
y[7] += (w[28]*xj0+w[29]*xj1+w[30]*xj2+w[31]*xj3);
|
||||||
|
w += 32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i=0;i<rows;i++) out[i] *= scale[i];
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static inline void sparse_cgemv8x4(float *out, const opus_int8 *w, const int *idx, const float *scale, int rows, int cols, const float *_x)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
opus_int8 x[MAX_INPUTS];
|
||||||
|
for (i=0;i<rows;i++) out[i] = 0;
|
||||||
|
for (i=0;i<cols;i++) x[i] = (int)floor(.5+127*_x[i]);
|
||||||
|
for (i=0;i<rows;i+=8)
|
||||||
|
{
|
||||||
|
int colblocks;
|
||||||
|
colblocks = *idx++;
|
||||||
|
for (j=0;j<colblocks;j++)
|
||||||
|
{
|
||||||
|
int pos;
|
||||||
|
float * restrict y;
|
||||||
|
int xj0, xj1, xj2, xj3;
|
||||||
|
pos = (*idx++);
|
||||||
|
xj0 = x[pos+0];
|
||||||
|
xj1 = x[pos+1];
|
||||||
|
xj2 = x[pos+2];
|
||||||
|
xj3 = x[pos+3];
|
||||||
|
y = &out[i];
|
||||||
|
y[0] += (w[0]*xj0+w[1]*xj1+w[2]*xj2+w[3]*xj3);
|
||||||
|
y[1] += (w[4]*xj0+w[5]*xj1+w[6]*xj2+w[7]*xj3);
|
||||||
|
y[2] += (w[8]*xj0+w[9]*xj1+w[10]*xj2+w[11]*xj3);
|
||||||
|
y[3] += (w[12]*xj0+w[13]*xj1+w[14]*xj2+w[15]*xj3);
|
||||||
|
y[4] += (w[16]*xj0+w[17]*xj1+w[18]*xj2+w[19]*xj3);
|
||||||
|
y[5] += (w[20]*xj0+w[21]*xj1+w[22]*xj2+w[23]*xj3);
|
||||||
|
y[6] += (w[24]*xj0+w[25]*xj1+w[26]*xj2+w[27]*xj3);
|
||||||
|
y[7] += (w[28]*xj0+w[29]*xj1+w[30]*xj2+w[31]*xj3);
|
||||||
|
w += 32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i=0;i<rows;i++) out[i] *= scale[i];
|
||||||
|
}
|
||||||
|
static inline void cgemv8x4(float *out, const opus_int8 *w, const float *scale, int rows, int cols, const float *_x)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
opus_int8 x[MAX_INPUTS];
|
||||||
|
for (i=0;i<rows;i++) out[i] = 0;
|
||||||
|
for (i=0;i<cols;i++) x[i] = (int)floor(.5+127*_x[i]);
|
||||||
|
for (i=0;i<rows;i+=8)
|
||||||
|
{
|
||||||
|
for (j=0;j<cols;j+=4)
|
||||||
|
{
|
||||||
|
float *y;
|
||||||
|
float xj0, xj1, xj2, xj3;
|
||||||
|
xj0 = x[j+0];
|
||||||
|
xj1 = x[j+1];
|
||||||
|
xj2 = x[j+2];
|
||||||
|
xj3 = x[j+3];
|
||||||
|
y = &out[i];
|
||||||
|
y[0] += (w[0]*xj0+w[1]*xj1+w[2]*xj2+w[3]*xj3);
|
||||||
|
y[1] += (w[4]*xj0+w[5]*xj1+w[6]*xj2+w[7]*xj3);
|
||||||
|
y[2] += (w[8]*xj0+w[9]*xj1+w[10]*xj2+w[11]*xj3);
|
||||||
|
y[3] += (w[12]*xj0+w[13]*xj1+w[14]*xj2+w[15]*xj3);
|
||||||
|
y[4] += (w[16]*xj0+w[17]*xj1+w[18]*xj2+w[19]*xj3);
|
||||||
|
y[5] += (w[20]*xj0+w[21]*xj1+w[22]*xj2+w[23]*xj3);
|
||||||
|
y[6] += (w[24]*xj0+w[25]*xj1+w[26]*xj2+w[27]*xj3);
|
||||||
|
y[7] += (w[28]*xj0+w[29]*xj1+w[30]*xj2+w[31]*xj3);
|
||||||
|
w += 32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i=0;i<rows;i++) out[i] *= scale[i];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* No AVX2/FMA support */
|
||||||
|
#ifndef LPCNET_TEST
|
||||||
|
static inline float lpcnet_exp2(float x)
|
||||||
|
{
|
||||||
|
int integer;
|
||||||
|
float frac;
|
||||||
|
union {
|
||||||
|
float f;
|
||||||
|
opus_uint32 i;
|
||||||
|
} res;
|
||||||
|
integer = floor(x);
|
||||||
|
if (integer < -50)
|
||||||
|
return 0;
|
||||||
|
frac = x-integer;
|
||||||
|
/* K0 = 1, K1 = log(2), K2 = 3-4*log(2), K3 = 3*log(2) - 2 */
|
||||||
|
res.f = 0.99992522f + frac * (0.69583354f
|
||||||
|
+ frac * (0.22606716f + 0.078024523f*frac));
|
||||||
|
res.i = (res.i + (integer<<23)) & 0x7fffffff;
|
||||||
|
return res.f;
|
||||||
|
}
|
||||||
|
#define lpcnet_exp(x) lpcnet_exp2((x)*1.44269504f)
|
||||||
|
|
||||||
|
#define fmadd(a, b, c) ((a)*(b)+(c))
|
||||||
|
static OPUS_INLINE float tanh_approx(float x)
|
||||||
|
{
|
||||||
|
const float N0 = 952.52801514f;
|
||||||
|
const float N1 = 96.39235687f;
|
||||||
|
const float N2 = 0.60863042f;
|
||||||
|
const float D0 = 952.72399902f;
|
||||||
|
const float D1 = 413.36801147f;
|
||||||
|
const float D2 = 11.88600922f;
|
||||||
|
float X2, num, den;
|
||||||
|
X2 = x*x;
|
||||||
|
num = fmadd(fmadd(N2, X2, N1), X2, N0);
|
||||||
|
den = fmadd(fmadd(D2, X2, D1), X2, D0);
|
||||||
|
num = num*x/den;
|
||||||
|
return MAX32(-1.f, MIN32(1.f, num));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline float sigmoid_approx(float x)
|
||||||
|
{
|
||||||
|
return .5f + .5f*tanh_approx(.5f*x);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void softmax(float *y, const float *x, int N)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i=0;i<N;i++)
|
||||||
|
y[i] = lpcnet_exp(x[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void vec_tanh(float *y, const float *x, int N)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i=0;i<N;i++)
|
||||||
|
{
|
||||||
|
y[i] = tanh_approx(x[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void vec_sigmoid(float *y, const float *x, int N)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i=0;i<N;i++)
|
||||||
|
{
|
||||||
|
y[i] = sigmoid_approx(x[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SCALE (128.f*127.f)
|
||||||
|
#define SCALE_1 (1.f/128.f/127.f)
|
||||||
|
|
||||||
|
#endif /*no optimizations*/
|
||||||
|
#endif /*VEC_H*/
|
||||||
884
third_party/rnnoise/src/vec_avx.h
vendored
Normal file
884
third_party/rnnoise/src/vec_avx.h
vendored
Normal file
@@ -0,0 +1,884 @@
|
|||||||
|
/* Copyright (c) 2018 Mozilla
|
||||||
|
2012-2017 Jean-Marc Valin */
|
||||||
|
/*
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
- Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||||||
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
AVX implementation of vector operations, compile with -mavx
|
||||||
|
AVX2/FMA implementation of vector operations, compile with -mavx2 -mfma
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef VEC_AVX_H
|
||||||
|
#define VEC_AVX_H
|
||||||
|
|
||||||
|
#include <immintrin.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "x86/x86cpu.h"
|
||||||
|
|
||||||
|
#define MAX_INPUTS (2048)
|
||||||
|
|
||||||
|
#define USE_SU_BIAS
|
||||||
|
|
||||||
|
#ifndef __SSE_4_1__
|
||||||
|
static inline __m128 mm_floor_ps(__m128 x) {
|
||||||
|
__m128 half = _mm_set1_ps(0.5);
|
||||||
|
return _mm_cvtepi32_ps(_mm_cvtps_epi32(_mm_sub_ps(x, half)));
|
||||||
|
}
|
||||||
|
#undef _mm_floor_ps
|
||||||
|
#define _mm_floor_ps(x) mm_floor_ps(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* If we don't have AVX available, emulate what we need with SSE up to 4.1. */
|
||||||
|
#ifndef __AVX__
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
__m128 lo;
|
||||||
|
__m128 hi;
|
||||||
|
} mm256_emu;
|
||||||
|
#define __m256 mm256_emu
|
||||||
|
|
||||||
|
static inline mm256_emu mm256_loadu_ps(const float *src) {
|
||||||
|
mm256_emu ret;
|
||||||
|
ret.lo = _mm_loadu_ps(&src[0]);
|
||||||
|
ret.hi = _mm_loadu_ps(&src[4]);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#define _mm256_loadu_ps(src) mm256_loadu_ps(src)
|
||||||
|
|
||||||
|
|
||||||
|
static inline void mm256_storeu_ps(float *dst, mm256_emu src) {
|
||||||
|
_mm_storeu_ps(dst, src.lo);
|
||||||
|
_mm_storeu_ps(&dst[4], src.hi);
|
||||||
|
}
|
||||||
|
#define _mm256_storeu_ps(dst, src) mm256_storeu_ps(dst, src)
|
||||||
|
|
||||||
|
|
||||||
|
static inline mm256_emu mm256_setzero_ps(void) {
|
||||||
|
mm256_emu ret;
|
||||||
|
ret.lo = _mm_setzero_ps();
|
||||||
|
ret.hi = ret.lo;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#define _mm256_setzero_ps mm256_setzero_ps
|
||||||
|
|
||||||
|
static inline mm256_emu mm256_broadcast_ss(const float *x) {
|
||||||
|
mm256_emu ret;
|
||||||
|
ret.lo = _mm_set1_ps(*x);
|
||||||
|
ret.hi = ret.lo;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#define _mm256_broadcast_ss(x) mm256_broadcast_ss(x)
|
||||||
|
|
||||||
|
static inline mm256_emu mm256_set1_ps(float x) {
|
||||||
|
mm256_emu ret;
|
||||||
|
ret.lo = _mm_set1_ps(x);
|
||||||
|
ret.hi = ret.lo;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#define _mm256_set1_ps(x) mm256_set1_ps(x)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static inline mm256_emu mm256_mul_ps(mm256_emu a, mm256_emu b) {
|
||||||
|
mm256_emu ret;
|
||||||
|
ret.lo = _mm_mul_ps(a.lo, b.lo);
|
||||||
|
ret.hi = _mm_mul_ps(a.hi, b.hi);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#define _mm256_mul_ps(a,b) mm256_mul_ps(a,b)
|
||||||
|
|
||||||
|
static inline mm256_emu mm256_add_ps(mm256_emu a, mm256_emu b) {
|
||||||
|
mm256_emu ret;
|
||||||
|
ret.lo = _mm_add_ps(a.lo, b.lo);
|
||||||
|
ret.hi = _mm_add_ps(a.hi, b.hi);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#define _mm256_add_ps(a,b) mm256_add_ps(a,b)
|
||||||
|
|
||||||
|
|
||||||
|
static inline mm256_emu mm256_max_ps(mm256_emu a, mm256_emu b) {
|
||||||
|
mm256_emu ret;
|
||||||
|
ret.lo = _mm_max_ps(a.lo, b.lo);
|
||||||
|
ret.hi = _mm_max_ps(a.hi, b.hi);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#define _mm256_max_ps(a,b) mm256_max_ps(a,b)
|
||||||
|
|
||||||
|
static inline mm256_emu mm256_min_ps(mm256_emu a, mm256_emu b) {
|
||||||
|
mm256_emu ret;
|
||||||
|
ret.lo = _mm_min_ps(a.lo, b.lo);
|
||||||
|
ret.hi = _mm_min_ps(a.hi, b.hi);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#define _mm256_min_ps(a,b) mm256_min_ps(a,b)
|
||||||
|
|
||||||
|
static inline mm256_emu mm256_rcp_ps(mm256_emu a) {
|
||||||
|
mm256_emu ret;
|
||||||
|
ret.lo = _mm_rcp_ps(a.lo);
|
||||||
|
ret.hi = _mm_rcp_ps(a.hi);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#define _mm256_rcp_ps(a) mm256_rcp_ps(a)
|
||||||
|
|
||||||
|
|
||||||
|
static inline __m128 mm256_extractf128_ps(mm256_emu x, int i) {
|
||||||
|
return (i==0) ? x.lo : x.hi;
|
||||||
|
}
|
||||||
|
#undef _mm256_extractf128_ps
|
||||||
|
#define _mm256_extractf128_ps(x,i) mm256_extractf128_ps(x,i)
|
||||||
|
|
||||||
|
static inline mm256_emu mm256_insertf128_ps(mm256_emu dst, __m128 src, int i) {
|
||||||
|
if (i==0) dst.lo = src;
|
||||||
|
else dst.hi = src;
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
#undef _mm256_insertf128_ps
|
||||||
|
#define _mm256_insertf128_ps(dst,src,i) mm256_insertf128_ps(dst,src,i)
|
||||||
|
|
||||||
|
#endif /* __AVX__ */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* If we don't have AVX2 available, emulate what we need with SSE up to 4.1. */
|
||||||
|
#ifndef __AVX2__
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
__m128i lo;
|
||||||
|
__m128i hi;
|
||||||
|
} mm256i_emu;
|
||||||
|
typedef __m256i real_m256i;
|
||||||
|
#define __m256i mm256i_emu
|
||||||
|
|
||||||
|
static inline mm256i_emu mm256_setzero_si256(void) {
|
||||||
|
mm256i_emu ret;
|
||||||
|
ret.lo = _mm_setzero_si128();
|
||||||
|
ret.hi = ret.lo;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#define _mm256_setzero_si256 mm256_setzero_si256
|
||||||
|
|
||||||
|
|
||||||
|
static inline mm256i_emu mm256_loadu_si256(const mm256i_emu *src) {
|
||||||
|
mm256i_emu ret;
|
||||||
|
ret.lo = _mm_loadu_si128((const __m128i*)src);
|
||||||
|
ret.hi = _mm_loadu_si128(&((const __m128i*)src)[1]);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#define _mm256_loadu_si256(src) mm256_loadu_si256(src)
|
||||||
|
|
||||||
|
|
||||||
|
static inline void mm256_storeu_si256(mm256i_emu *dst, mm256i_emu src) {
|
||||||
|
_mm_storeu_si128((__m128i*)dst, src.lo);
|
||||||
|
_mm_storeu_si128(&((__m128i*)dst)[1], src.hi);
|
||||||
|
}
|
||||||
|
#define _mm256_storeu_si256(dst, src) mm256_storeu_si256(dst, src)
|
||||||
|
|
||||||
|
|
||||||
|
static inline mm256i_emu mm256_broadcastd_epi32(__m128i x) {
|
||||||
|
mm256i_emu ret;
|
||||||
|
ret.hi = ret.lo = _mm_shuffle_epi32(x, 0);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#define _mm256_broadcastd_epi32(x) mm256_broadcastd_epi32(x)
|
||||||
|
|
||||||
|
|
||||||
|
static inline mm256i_emu mm256_set1_epi32(int x) {
|
||||||
|
mm256i_emu ret;
|
||||||
|
ret.lo = _mm_set1_epi32(x);
|
||||||
|
ret.hi = ret.lo;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#define _mm256_set1_epi32(x) mm256_set1_epi32(x)
|
||||||
|
|
||||||
|
static inline mm256i_emu mm256_set1_epi16(int x) {
|
||||||
|
mm256i_emu ret;
|
||||||
|
ret.lo = _mm_set1_epi16(x);
|
||||||
|
ret.hi = ret.lo;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#define _mm256_set1_epi16(x) mm256_set1_epi16(x)
|
||||||
|
|
||||||
|
|
||||||
|
static inline mm256i_emu mm256_add_epi32(mm256i_emu a, mm256i_emu b) {
|
||||||
|
mm256i_emu ret;
|
||||||
|
ret.lo = _mm_add_epi32(a.lo, b.lo);
|
||||||
|
ret.hi = _mm_add_epi32(a.hi, b.hi);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#define _mm256_add_epi32(a,b) mm256_add_epi32(a,b)
|
||||||
|
|
||||||
|
static inline mm256i_emu mm256_madd_epi16(mm256i_emu a, mm256i_emu b) {
|
||||||
|
mm256i_emu ret;
|
||||||
|
ret.lo = _mm_madd_epi16(a.lo, b.lo);
|
||||||
|
ret.hi = _mm_madd_epi16(a.hi, b.hi);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#define _mm256_madd_epi16(a,b) mm256_madd_epi16(a,b)
|
||||||
|
|
||||||
|
static inline mm256i_emu mm256_maddubs_epi16(mm256i_emu a, mm256i_emu b) {
|
||||||
|
mm256i_emu ret;
|
||||||
|
ret.lo = _mm_maddubs_epi16(a.lo, b.lo);
|
||||||
|
ret.hi = _mm_maddubs_epi16(a.hi, b.hi);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#define _mm256_maddubs_epi16(a,b) mm256_maddubs_epi16(a,b)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Emulating the conversion functions is tricky because they use __m256i but are defined in AVX.
|
||||||
|
So we need to make a special when only AVX is available. */
|
||||||
|
#ifdef __AVX__
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
mm256i_emu fake;
|
||||||
|
real_m256i real;
|
||||||
|
} mm256_union;
|
||||||
|
|
||||||
|
static inline __m256 mm256_cvtepi32_ps(mm256i_emu a) {
|
||||||
|
mm256_union src;
|
||||||
|
src.fake = a;
|
||||||
|
return _mm256_cvtepi32_ps(src.real);
|
||||||
|
}
|
||||||
|
#define _mm256_cvtepi32_ps(a) mm256_cvtepi32_ps(a)
|
||||||
|
|
||||||
|
static inline mm256i_emu mm256_cvtps_epi32(__m256 a) {
|
||||||
|
mm256_union ret;
|
||||||
|
ret.real = _mm256_cvtps_epi32(a);
|
||||||
|
return ret.fake;
|
||||||
|
}
|
||||||
|
#define _mm256_cvtps_epi32(a) mm256_cvtps_epi32(a)
|
||||||
|
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline mm256_emu mm256_cvtepi32_ps(mm256i_emu a) {
|
||||||
|
mm256_emu ret;
|
||||||
|
ret.lo = _mm_cvtepi32_ps(a.lo);
|
||||||
|
ret.hi = _mm_cvtepi32_ps(a.hi);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#define _mm256_cvtepi32_ps(a) mm256_cvtepi32_ps(a)
|
||||||
|
|
||||||
|
static inline mm256i_emu mm256_cvtps_epi32(mm256_emu a) {
|
||||||
|
mm256i_emu ret;
|
||||||
|
ret.lo = _mm_cvtps_epi32(a.lo);
|
||||||
|
ret.hi = _mm_cvtps_epi32(a.hi);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#define _mm256_cvtps_epi32(a) mm256_cvtps_epi32(a)
|
||||||
|
|
||||||
|
#endif /* __AVX__ */
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __AVX2__ */
|
||||||
|
|
||||||
|
/* In case we don't have FMA, make it a mul and an add. */
|
||||||
|
#if !(defined(__FMA__) && defined(__AVX__))
|
||||||
|
#define _mm256_fmadd_ps(a,b,c) _mm256_add_ps(_mm256_mul_ps(a, b), c)
|
||||||
|
#define _mm_fmadd_ps(a,b,c) _mm_add_ps(_mm_mul_ps(a, b), c)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __AVX2__
|
||||||
|
static inline __m256 exp8_approx(__m256 X)
|
||||||
|
{
|
||||||
|
const __m256 K0 = _mm256_set1_ps(0.99992522f);
|
||||||
|
const __m256 K1 = _mm256_set1_ps(0.69583354f);
|
||||||
|
const __m256 K2 = _mm256_set1_ps(0.22606716f);
|
||||||
|
const __m256 K3 = _mm256_set1_ps(0.078024523f);
|
||||||
|
const __m256 log2_E = _mm256_set1_ps(1.44269504f);
|
||||||
|
const __m256 max_in = _mm256_set1_ps(50.f);
|
||||||
|
const __m256 min_in = _mm256_set1_ps(-50.f);
|
||||||
|
__m256 XF, Y;
|
||||||
|
__m256i I;
|
||||||
|
X = _mm256_mul_ps(X, log2_E);
|
||||||
|
X = _mm256_max_ps(min_in, _mm256_min_ps(max_in, X));
|
||||||
|
XF = _mm256_floor_ps(X);
|
||||||
|
I = _mm256_cvtps_epi32(XF);
|
||||||
|
X = _mm256_sub_ps(X, XF);
|
||||||
|
Y = _mm256_fmadd_ps(_mm256_fmadd_ps(_mm256_fmadd_ps(K3, X, K2), X, K1), X, K0);
|
||||||
|
I = _mm256_slli_epi32(I, 23);
|
||||||
|
Y = _mm256_castsi256_ps(_mm256_add_epi32(I, _mm256_castps_si256(Y)));
|
||||||
|
return Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void vector_ps_to_epi8(unsigned char *x, const float *_x, int len) {
|
||||||
|
int i;
|
||||||
|
__m256 const127 = _mm256_set1_ps(127.f);
|
||||||
|
for (i=0;i<len;i+=8) {
|
||||||
|
__m256 xf;
|
||||||
|
__m256i xi;
|
||||||
|
xf = _mm256_loadu_ps(&_x[i]);
|
||||||
|
xf = _mm256_fmadd_ps(xf, const127, const127);
|
||||||
|
xi = _mm256_cvtps_epi32(xf);
|
||||||
|
xi = _mm256_packus_epi32(xi, _mm256_setzero_si256());
|
||||||
|
xi = _mm256_permute4x64_epi64(xi, 0xD8);
|
||||||
|
xi = _mm256_packus_epi16(xi, _mm256_setzero_si256());
|
||||||
|
xi = _mm256_permutevar8x32_epi32(xi, _mm256_setr_epi32(0,1, 0,0, 0,0, 0,0));
|
||||||
|
_mm256_storeu_si256 ((__m256i *)(void*)&x[i], xi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
static inline __m128 exp4_approx(__m128 X)
|
||||||
|
{
|
||||||
|
const __m128 K0 = _mm_set1_ps(0.99992522f);
|
||||||
|
const __m128 K1 = _mm_set1_ps(0.69583354f);
|
||||||
|
const __m128 K2 = _mm_set1_ps(0.22606716f);
|
||||||
|
const __m128 K3 = _mm_set1_ps(0.078024523f);
|
||||||
|
const __m128 log2_E = _mm_set1_ps(1.44269504);
|
||||||
|
const __m128 max_in = _mm_set1_ps(50.f);
|
||||||
|
const __m128 min_in = _mm_set1_ps(-50.f);
|
||||||
|
const __m128i mask = _mm_set1_epi32(0x7fffffff);
|
||||||
|
__m128 XF, Y;
|
||||||
|
__m128i I;
|
||||||
|
X = _mm_mul_ps(X, log2_E);
|
||||||
|
X = _mm_max_ps(min_in, _mm_min_ps(max_in, X));
|
||||||
|
XF = _mm_floor_ps(X);
|
||||||
|
I = _mm_cvtps_epi32(XF);
|
||||||
|
X = _mm_sub_ps(X, XF);
|
||||||
|
Y = _mm_fmadd_ps(_mm_fmadd_ps(_mm_fmadd_ps(K3, X, K2), X, K1), X, K0);
|
||||||
|
I = _mm_slli_epi32(I, 23);
|
||||||
|
Y = _mm_castsi128_ps(_mm_and_si128(mask, _mm_add_epi32(I, _mm_castps_si128(Y))));
|
||||||
|
return Y;
|
||||||
|
}
|
||||||
|
static inline __m256 exp8_approx(__m256 X)
|
||||||
|
{
|
||||||
|
__m256 Y;
|
||||||
|
__m128 Xhi, Xlo, Yhi, Ylo;
|
||||||
|
Xhi = _mm256_extractf128_ps(X, 1);
|
||||||
|
Xlo = _mm256_extractf128_ps(X, 0);
|
||||||
|
Yhi = exp4_approx(Xhi);
|
||||||
|
Ylo = exp4_approx(Xlo);
|
||||||
|
Y = _mm256_insertf128_ps(_mm256_setzero_ps(), Yhi, 1);
|
||||||
|
Y = _mm256_insertf128_ps(Y, Ylo, 0);
|
||||||
|
return Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void vector_ps_to_epi8(unsigned char *x, const float *_x, int len) {
|
||||||
|
int i;
|
||||||
|
for (i=0;i<len;i++) x[i] = 127+(int)floor(.5+127*_x[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __AVX__
|
||||||
|
|
||||||
|
/* Approximating tanh() using a Padé-like rational function:
|
||||||
|
tanh(x) ~= x * (N0 + N1*x^2 + N2*x^4)/(D0 + D1*x^2 + D2*x^4)
|
||||||
|
subject to the +/- 1 bounds.
|
||||||
|
The coefficients were determined by gradient descent trying to minimize
|
||||||
|
the maximum deviation over the whole range (this is only possible because
|
||||||
|
of the bounds). The max error is around 3e-4 and is dominated by the
|
||||||
|
reciprocal approximation (the max error of the rational function is
|
||||||
|
around 6e-5).
|
||||||
|
*/
|
||||||
|
static inline __m256 tanh8_approx(__m256 X)
|
||||||
|
{
|
||||||
|
const __m256 N0 = _mm256_set1_ps(952.52801514f);
|
||||||
|
const __m256 N1 = _mm256_set1_ps(96.39235687f);
|
||||||
|
const __m256 N2 = _mm256_set1_ps(0.60863042f);
|
||||||
|
const __m256 D0 = _mm256_set1_ps(952.72399902f);
|
||||||
|
const __m256 D1 = _mm256_set1_ps(413.36801147f);
|
||||||
|
const __m256 D2 = _mm256_set1_ps(11.88600922f);
|
||||||
|
const __m256 max_out = _mm256_set1_ps(1.f);
|
||||||
|
const __m256 min_out = _mm256_set1_ps(-1.f);
|
||||||
|
__m256 X2, num, den;
|
||||||
|
X2 = _mm256_mul_ps(X, X);
|
||||||
|
num = _mm256_fmadd_ps(_mm256_fmadd_ps(N2, X2, N1), X2, N0);
|
||||||
|
den = _mm256_fmadd_ps(_mm256_fmadd_ps(D2, X2, D1), X2, D0);
|
||||||
|
num = _mm256_mul_ps(num, X);
|
||||||
|
den = _mm256_rcp_ps(den);
|
||||||
|
num = _mm256_mul_ps(num, den);
|
||||||
|
return _mm256_max_ps(min_out, _mm256_min_ps(max_out, num));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sigmoid approximation using a Padé-like rational function:
|
||||||
|
1/(1+exp(-x)) ~= 0.5 + x * (N0 + N1*x^2 + N2*x^4)/(D0 + D1*x^2 + D2*x^4)
|
||||||
|
subject to the [0, 1] bounds.
|
||||||
|
The coefficients are directly derived by dividing the tanh() coefficients
|
||||||
|
by powers of two to get the correct scaling. The max error is around 1.5e-4
|
||||||
|
and is dominated by the reciprocal approximation (the max error of the
|
||||||
|
rational function is around 3e-5).
|
||||||
|
*/
|
||||||
|
static inline __m256 sigmoid8_approx(__m256 X)
|
||||||
|
{
|
||||||
|
const __m256 N0 = _mm256_set1_ps(238.13200378f);
|
||||||
|
const __m256 N1 = _mm256_set1_ps(6.02452230f);
|
||||||
|
const __m256 N2 = _mm256_set1_ps(0.00950985f);
|
||||||
|
const __m256 D0 = _mm256_set1_ps(952.72399902f);
|
||||||
|
const __m256 D1 = _mm256_set1_ps(103.34200287f);
|
||||||
|
const __m256 D2 = _mm256_set1_ps(0.74287558f);
|
||||||
|
const __m256 half = _mm256_set1_ps(0.5);
|
||||||
|
const __m256 max_out = _mm256_set1_ps(1.f);
|
||||||
|
const __m256 min_out = _mm256_set1_ps(0.f);
|
||||||
|
__m256 X2, num, den;
|
||||||
|
X2 = _mm256_mul_ps(X, X);
|
||||||
|
num = _mm256_fmadd_ps(_mm256_fmadd_ps(N2, X2, N1), X2, N0);
|
||||||
|
den = _mm256_fmadd_ps(_mm256_fmadd_ps(D2, X2, D1), X2, D0);
|
||||||
|
num = _mm256_mul_ps(num, X);
|
||||||
|
den = _mm256_rcp_ps(den);
|
||||||
|
num = _mm256_fmadd_ps(num, den, half);
|
||||||
|
return _mm256_max_ps(min_out, _mm256_min_ps(max_out, num));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline float tanh_approx(float x)
|
||||||
|
{
|
||||||
|
float out[8];
|
||||||
|
__m256 X, Y;
|
||||||
|
X = _mm256_set1_ps(x);
|
||||||
|
Y = tanh8_approx(X);
|
||||||
|
_mm256_storeu_ps(out, Y);
|
||||||
|
return out[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline float sigmoid_approx(float x)
|
||||||
|
{
|
||||||
|
float out[8];
|
||||||
|
__m256 X, Y;
|
||||||
|
X = _mm256_set1_ps(x);
|
||||||
|
Y = sigmoid8_approx(X);
|
||||||
|
_mm256_storeu_ps(out, Y);
|
||||||
|
return out[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline __m128 tanh4_approx(__m128 X)
|
||||||
|
{
|
||||||
|
const __m128 N0 = _mm_set1_ps(952.52801514f);
|
||||||
|
const __m128 N1 = _mm_set1_ps(96.39235687f);
|
||||||
|
const __m128 N2 = _mm_set1_ps(0.60863042f);
|
||||||
|
const __m128 D0 = _mm_set1_ps(952.72399902f);
|
||||||
|
const __m128 D1 = _mm_set1_ps(413.36801147f);
|
||||||
|
const __m128 D2 = _mm_set1_ps(11.88600922f);
|
||||||
|
const __m128 max_out = _mm_set1_ps(1.f);
|
||||||
|
const __m128 min_out = _mm_set1_ps(-1.f);
|
||||||
|
__m128 X2, num, den;
|
||||||
|
X2 = _mm_mul_ps(X, X);
|
||||||
|
num = _mm_fmadd_ps(_mm_fmadd_ps(N2, X2, N1), X2, N0);
|
||||||
|
den = _mm_fmadd_ps(_mm_fmadd_ps(D2, X2, D1), X2, D0);
|
||||||
|
num = _mm_mul_ps(num, X);
|
||||||
|
den = _mm_rcp_ps(den);
|
||||||
|
num = _mm_mul_ps(num, den);
|
||||||
|
return _mm_max_ps(min_out, _mm_min_ps(max_out, num));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __m128 sigmoid4_approx(__m128 X)
|
||||||
|
{
|
||||||
|
const __m128 N0 = _mm_set1_ps(238.13200378f);
|
||||||
|
const __m128 N1 = _mm_set1_ps(6.02452230f);
|
||||||
|
const __m128 N2 = _mm_set1_ps(0.00950985f);
|
||||||
|
const __m128 D0 = _mm_set1_ps(952.72399902f);
|
||||||
|
const __m128 D1 = _mm_set1_ps(103.34200287f);
|
||||||
|
const __m128 D2 = _mm_set1_ps(0.74287558f);
|
||||||
|
const __m128 half = _mm_set1_ps(0.5);
|
||||||
|
const __m128 max_out = _mm_set1_ps(1.f);
|
||||||
|
const __m128 min_out = _mm_set1_ps(0.f);
|
||||||
|
__m128 X2, num, den;
|
||||||
|
X2 = _mm_mul_ps(X, X);
|
||||||
|
num = _mm_fmadd_ps(_mm_fmadd_ps(N2, X2, N1), X2, N0);
|
||||||
|
den = _mm_fmadd_ps(_mm_fmadd_ps(D2, X2, D1), X2, D0);
|
||||||
|
num = _mm_mul_ps(num, X);
|
||||||
|
den = _mm_rcp_ps(den);
|
||||||
|
num = _mm_fmadd_ps(num, den, half);
|
||||||
|
return _mm_max_ps(min_out, _mm_min_ps(max_out, num));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline float tanh_approx(float x)
|
||||||
|
{
|
||||||
|
float out[4];
|
||||||
|
__m128 X, Y;
|
||||||
|
X = _mm_set1_ps(x);
|
||||||
|
Y = tanh4_approx(X);
|
||||||
|
_mm_storeu_ps(out, Y);
|
||||||
|
return out[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline float sigmoid_approx(float x)
|
||||||
|
{
|
||||||
|
float out[4];
|
||||||
|
__m128 X, Y;
|
||||||
|
X = _mm_set1_ps(x);
|
||||||
|
Y = sigmoid4_approx(X);
|
||||||
|
_mm_storeu_ps(out, Y);
|
||||||
|
return out[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline float lpcnet_exp(float x)
|
||||||
|
{
|
||||||
|
float out[8];
|
||||||
|
__m256 X, Y;
|
||||||
|
X = _mm256_set1_ps(x);
|
||||||
|
Y = exp8_approx(X);
|
||||||
|
_mm256_storeu_ps(out, Y);
|
||||||
|
return out[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void softmax(float *y, const float *x, int N)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i=0;i<N-7;i+=8)
|
||||||
|
{
|
||||||
|
__m256 X, Y;
|
||||||
|
X = _mm256_loadu_ps(&x[i]);
|
||||||
|
Y = exp8_approx(X);
|
||||||
|
_mm256_storeu_ps(&y[i], Y);
|
||||||
|
}
|
||||||
|
for (;i<N;i++)
|
||||||
|
y[i] = lpcnet_exp(x[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __AVX__
|
||||||
|
static inline void vec_tanh(float *y, const float *x, int N)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i=0;i<N-7;i+=8)
|
||||||
|
{
|
||||||
|
__m256 X, Y;
|
||||||
|
X = _mm256_loadu_ps(&x[i]);
|
||||||
|
Y = tanh8_approx(X);
|
||||||
|
_mm256_storeu_ps(&y[i], Y);
|
||||||
|
}
|
||||||
|
for (;i<N;i++)
|
||||||
|
{
|
||||||
|
y[i] = tanh_approx(x[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void vec_sigmoid(float *y, const float *x, int N)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i=0;i<N-7;i+=8)
|
||||||
|
{
|
||||||
|
__m256 X, Y;
|
||||||
|
X = _mm256_loadu_ps(&x[i]);
|
||||||
|
Y = sigmoid8_approx(X);
|
||||||
|
_mm256_storeu_ps(&y[i], Y);
|
||||||
|
}
|
||||||
|
for (;i<N;i++)
|
||||||
|
{
|
||||||
|
y[i] = sigmoid_approx(x[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static inline void vec_tanh(float *y, const float *x, int N)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i=0;i<N-3;i+=4)
|
||||||
|
{
|
||||||
|
__m128 X, Y;
|
||||||
|
X = _mm_loadu_ps(&x[i]);
|
||||||
|
Y = tanh4_approx(X);
|
||||||
|
_mm_storeu_ps(&y[i], Y);
|
||||||
|
}
|
||||||
|
for (;i<N;i++)
|
||||||
|
{
|
||||||
|
y[i] = tanh_approx(x[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void vec_sigmoid(float *y, const float *x, int N)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i=0;i<N-3;i+=4)
|
||||||
|
{
|
||||||
|
__m128 X, Y;
|
||||||
|
X = _mm_loadu_ps(&x[i]);
|
||||||
|
Y = sigmoid4_approx(X);
|
||||||
|
_mm_storeu_ps(&y[i], Y);
|
||||||
|
}
|
||||||
|
for (;i<N;i++)
|
||||||
|
{
|
||||||
|
y[i] = sigmoid_approx(x[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__AVXVNNI__) || defined(__AVX512VNNI__)
|
||||||
|
|
||||||
|
#define opus_mm256_dpbusds_epi32(src, a, b) _mm256_dpbusds_epi32(src, a, b)
|
||||||
|
|
||||||
|
#elif defined(__AVX2__)
|
||||||
|
|
||||||
|
static inline __m256i opus_mm256_dpbusds_epi32(__m256i src, __m256i a, __m256i b) {
|
||||||
|
__m256i ones, tmp;
|
||||||
|
ones = _mm256_set1_epi16(1);
|
||||||
|
tmp = _mm256_maddubs_epi16(a, b);
|
||||||
|
tmp = _mm256_madd_epi16(tmp, ones);
|
||||||
|
return _mm256_add_epi32(src, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(__SSSE3__)
|
||||||
|
|
||||||
|
static inline mm256i_emu opus_mm256_dpbusds_epi32(mm256i_emu src, mm256i_emu a, mm256i_emu b) {
|
||||||
|
mm256i_emu ones, tmp;
|
||||||
|
ones = _mm256_set1_epi16(1);
|
||||||
|
tmp = _mm256_maddubs_epi16(a, b);
|
||||||
|
tmp = _mm256_madd_epi16(tmp, ones);
|
||||||
|
return _mm256_add_epi32(src, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(__SSE2__)
|
||||||
|
|
||||||
|
static inline __m128i mm_dpbusds_epi32(__m128i src, __m128i a, __m128i b) {
|
||||||
|
__m128i ah, al, bh, bl, tmp;
|
||||||
|
ah = _mm_srli_epi16(a, 8);
|
||||||
|
bh = _mm_srai_epi16(b, 8);
|
||||||
|
al = _mm_srli_epi16(_mm_slli_epi16(a, 8), 8);
|
||||||
|
bl = _mm_srai_epi16(_mm_slli_epi16(b, 8), 8);
|
||||||
|
tmp = _mm_add_epi32(_mm_madd_epi16(ah, bh), _mm_madd_epi16(al, bl));
|
||||||
|
return _mm_add_epi32(src, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline mm256i_emu opus_mm256_dpbusds_epi32(mm256i_emu src, mm256i_emu a, mm256i_emu b) {
|
||||||
|
mm256i_emu res;
|
||||||
|
res.hi = mm_dpbusds_epi32(src.hi, a.hi, b.hi);
|
||||||
|
res.lo = mm_dpbusds_epi32(src.lo, a.lo, b.lo);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#error "No optimizations in vec_avx.h. This should never happen. "
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline void sgemv(float *out, const float *weights, int rows, int cols, int col_stride, const float *x)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
i=0;
|
||||||
|
for (;i<rows-15;i+=16)
|
||||||
|
{
|
||||||
|
float *y;
|
||||||
|
__m256 vy0, vy8;
|
||||||
|
y = &out[i];
|
||||||
|
vy0 = _mm256_setzero_ps();
|
||||||
|
vy8 = _mm256_setzero_ps();
|
||||||
|
for (j=0;j<cols;j++)
|
||||||
|
{
|
||||||
|
__m256 vxj;
|
||||||
|
__m256 vw;
|
||||||
|
vxj = _mm256_broadcast_ss(&x[j]);
|
||||||
|
|
||||||
|
vw = _mm256_loadu_ps(&weights[j*col_stride + i]);
|
||||||
|
vy0 = _mm256_fmadd_ps(vw, vxj, vy0);
|
||||||
|
|
||||||
|
vw = _mm256_loadu_ps(&weights[j*col_stride + i + 8]);
|
||||||
|
vy8 = _mm256_fmadd_ps(vw, vxj, vy8);
|
||||||
|
}
|
||||||
|
_mm256_storeu_ps (&y[0], vy0);
|
||||||
|
_mm256_storeu_ps (&y[8], vy8);
|
||||||
|
}
|
||||||
|
for (;i<rows-7;i+=8)
|
||||||
|
{
|
||||||
|
float *y;
|
||||||
|
__m256 vy0;
|
||||||
|
y = &out[i];
|
||||||
|
vy0 = _mm256_setzero_ps();
|
||||||
|
for (j=0;j<cols;j++)
|
||||||
|
{
|
||||||
|
__m256 vxj;
|
||||||
|
__m256 vw;
|
||||||
|
vxj = _mm256_broadcast_ss(&x[j]);
|
||||||
|
|
||||||
|
vw = _mm256_loadu_ps(&weights[j*col_stride + i]);
|
||||||
|
vy0 = _mm256_fmadd_ps(vw, vxj, vy0);
|
||||||
|
}
|
||||||
|
_mm256_storeu_ps (&y[0], vy0);
|
||||||
|
}
|
||||||
|
for (;i<rows-3;i+=4)
|
||||||
|
{
|
||||||
|
float *y;
|
||||||
|
__m128 vy0;
|
||||||
|
y = &out[i];
|
||||||
|
vy0 = _mm_setzero_ps();
|
||||||
|
for (j=0;j<cols;j++)
|
||||||
|
{
|
||||||
|
__m128 vxj;
|
||||||
|
__m128 vw;
|
||||||
|
vxj = _mm_set1_ps(x[j]);
|
||||||
|
|
||||||
|
vw = _mm_loadu_ps(&weights[j*col_stride + i]);
|
||||||
|
vy0 = _mm_fmadd_ps(vw, vxj, vy0);
|
||||||
|
}
|
||||||
|
_mm_storeu_ps (&y[0], vy0);
|
||||||
|
}
|
||||||
|
for (;i<rows;i++)
|
||||||
|
{
|
||||||
|
out[i] = 0;
|
||||||
|
for (j=0;j<cols;j++) out[i] += weights[j*col_stride + i]*x[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void sparse_sgemv8x4(float *out, const float *weights, const int *idx, int rows, const float *x)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
for (i=0;i<rows;i+=8)
|
||||||
|
{
|
||||||
|
float *y;
|
||||||
|
int cols;
|
||||||
|
__m256 vy0;
|
||||||
|
y = &out[i];
|
||||||
|
vy0 = _mm256_setzero_ps();
|
||||||
|
cols = *idx++;
|
||||||
|
for (j=0;j<cols;j++)
|
||||||
|
{
|
||||||
|
int id;
|
||||||
|
__m256 vxj;
|
||||||
|
__m256 vw;
|
||||||
|
id = *idx++;
|
||||||
|
vxj = _mm256_broadcast_ss(&x[id]);
|
||||||
|
vw = _mm256_loadu_ps(&weights[0]);
|
||||||
|
vy0 = _mm256_fmadd_ps(vw, vxj, vy0);
|
||||||
|
|
||||||
|
vxj = _mm256_broadcast_ss(&x[id+1]);
|
||||||
|
vw = _mm256_loadu_ps(&weights[8]);
|
||||||
|
vy0 = _mm256_fmadd_ps(vw, vxj, vy0);
|
||||||
|
|
||||||
|
vxj = _mm256_broadcast_ss(&x[id+2]);
|
||||||
|
vw = _mm256_loadu_ps(&weights[16]);
|
||||||
|
vy0 = _mm256_fmadd_ps(vw, vxj, vy0);
|
||||||
|
|
||||||
|
vxj = _mm256_broadcast_ss(&x[id+3]);
|
||||||
|
vw = _mm256_loadu_ps(&weights[24]);
|
||||||
|
vy0 = _mm256_fmadd_ps(vw, vxj, vy0);
|
||||||
|
|
||||||
|
weights += 32;
|
||||||
|
}
|
||||||
|
_mm256_storeu_ps (&y[0], vy0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void sparse_cgemv8x4(float *_out, const opus_int8 *w, const int *idx, const float *scale, int rows, int cols, const float *_x)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
unsigned char x[MAX_INPUTS];
|
||||||
|
/*for (i=0;i<cols;i++) x[i] = 127+floor(.5+127*_x[i]);*/
|
||||||
|
vector_ps_to_epi8(x, _x, cols);
|
||||||
|
for (i=0;i<rows;i+=8)
|
||||||
|
{
|
||||||
|
int colblocks;
|
||||||
|
__m256i vy0;
|
||||||
|
__m256 vout;
|
||||||
|
colblocks = *idx++;
|
||||||
|
vy0 = _mm256_setzero_si256();
|
||||||
|
j=0;
|
||||||
|
#if 1 /* Unrolling by 4 gives some gain, comment out if it does not. */
|
||||||
|
for (;j<colblocks-3;j+=4)
|
||||||
|
{
|
||||||
|
__m256i vxj;
|
||||||
|
__m256i vw;
|
||||||
|
vxj = _mm256_broadcastd_epi32(_mm_loadu_si32(&x[*idx++]));
|
||||||
|
vw = _mm256_loadu_si256((const __m256i *)(void*)w);
|
||||||
|
vy0 = opus_mm256_dpbusds_epi32(vy0, vxj, vw);
|
||||||
|
w += 32;
|
||||||
|
vxj = _mm256_broadcastd_epi32(_mm_loadu_si32(&x[*idx++]));
|
||||||
|
vw = _mm256_loadu_si256((const __m256i *)(void*)w);
|
||||||
|
vy0 = opus_mm256_dpbusds_epi32(vy0, vxj, vw);
|
||||||
|
w += 32;
|
||||||
|
vxj = _mm256_broadcastd_epi32(_mm_loadu_si32(&x[*idx++]));
|
||||||
|
vw = _mm256_loadu_si256((const __m256i *)(void*)w);
|
||||||
|
vy0 = opus_mm256_dpbusds_epi32(vy0, vxj, vw);
|
||||||
|
w += 32;
|
||||||
|
vxj = _mm256_broadcastd_epi32(_mm_loadu_si32(&x[*idx++]));
|
||||||
|
vw = _mm256_loadu_si256((const __m256i *)(void*)w);
|
||||||
|
vy0 = opus_mm256_dpbusds_epi32(vy0, vxj, vw);
|
||||||
|
w += 32;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
for (;j<colblocks;j++)
|
||||||
|
{
|
||||||
|
__m256i vxj;
|
||||||
|
__m256i vw;
|
||||||
|
vxj = _mm256_broadcastd_epi32(_mm_loadu_si32(&x[*idx++]));
|
||||||
|
vw = _mm256_loadu_si256((const __m256i *)(void*)w);
|
||||||
|
vy0 = opus_mm256_dpbusds_epi32(vy0, vxj, vw);
|
||||||
|
w += 32;
|
||||||
|
}
|
||||||
|
vout = _mm256_cvtepi32_ps(vy0);
|
||||||
|
vout = _mm256_mul_ps(vout, _mm256_loadu_ps(&scale[i]));
|
||||||
|
_mm256_storeu_ps(&_out[i], vout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static inline void cgemv8x4(float *_out, const opus_int8 *w, const float *scale, int rows, int cols, const float *_x)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
unsigned char x[MAX_INPUTS];
|
||||||
|
/*for (i=0;i<cols;i++) x[i] = 127+floor(.5+127*_x[i]);*/
|
||||||
|
vector_ps_to_epi8(x, _x, cols);
|
||||||
|
for (i=0;i<rows;i+=8)
|
||||||
|
{
|
||||||
|
__m256i vy0;
|
||||||
|
__m256 vout;
|
||||||
|
vy0 = _mm256_setzero_si256();
|
||||||
|
j=0;
|
||||||
|
#if 1 /* Unrolling by 4 gives some gain, comment out if it does not. */
|
||||||
|
for (;j<cols-12;j+=16)
|
||||||
|
{
|
||||||
|
__m256i vxj;
|
||||||
|
__m256i vw;
|
||||||
|
vxj = _mm256_broadcastd_epi32(_mm_loadu_si32(&x[j]));
|
||||||
|
vw = _mm256_loadu_si256((const __m256i *)(void*)w);
|
||||||
|
vy0 = opus_mm256_dpbusds_epi32(vy0, vxj, vw);
|
||||||
|
w += 32;
|
||||||
|
vxj = _mm256_broadcastd_epi32(_mm_loadu_si32(&x[j+4]));
|
||||||
|
vw = _mm256_loadu_si256((const __m256i *)(void*)w);
|
||||||
|
vy0 = opus_mm256_dpbusds_epi32(vy0, vxj, vw);
|
||||||
|
w += 32;
|
||||||
|
vxj = _mm256_broadcastd_epi32(_mm_loadu_si32(&x[j+8]));
|
||||||
|
vw = _mm256_loadu_si256((const __m256i *)(void*)w);
|
||||||
|
vy0 = opus_mm256_dpbusds_epi32(vy0, vxj, vw);
|
||||||
|
w += 32;
|
||||||
|
vxj = _mm256_broadcastd_epi32(_mm_loadu_si32(&x[j+12]));
|
||||||
|
vw = _mm256_loadu_si256((const __m256i *)(void*)w);
|
||||||
|
vy0 = opus_mm256_dpbusds_epi32(vy0, vxj, vw);
|
||||||
|
w += 32;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
for (;j<cols;j+=4)
|
||||||
|
{
|
||||||
|
__m256i vxj;
|
||||||
|
__m256i vw;
|
||||||
|
vxj = _mm256_broadcastd_epi32(_mm_loadu_si32(&x[j]));
|
||||||
|
vw = _mm256_loadu_si256((const __m256i *)(void*)w);
|
||||||
|
vy0 = opus_mm256_dpbusds_epi32(vy0, vxj, vw);
|
||||||
|
w += 32;
|
||||||
|
}
|
||||||
|
vout = _mm256_cvtepi32_ps(vy0);
|
||||||
|
vout = _mm256_mul_ps(vout, _mm256_loadu_ps(&scale[i]));
|
||||||
|
_mm256_storeu_ps(&_out[i], vout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SCALE (128.f*127.f)
|
||||||
|
#define SCALE_1 (1.f/128.f/127.f)
|
||||||
|
#define USE_SU_BIAS
|
||||||
|
|
||||||
|
|
||||||
|
#endif /*VEC_AVX_H*/
|
||||||
474
third_party/rnnoise/src/vec_neon.h
vendored
Normal file
474
third_party/rnnoise/src/vec_neon.h
vendored
Normal file
@@ -0,0 +1,474 @@
|
|||||||
|
/* Copyright (c) 2018 David Rowe
|
||||||
|
2018 Mozilla
|
||||||
|
2008-2011 Octasic Inc.
|
||||||
|
2012-2017 Jean-Marc Valin */
|
||||||
|
/*
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
- Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||||||
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
/* NEON support for ARM machines */
|
||||||
|
|
||||||
|
#ifndef VEC_NEON_H
|
||||||
|
#define VEC_NEON_H
|
||||||
|
|
||||||
|
#include <arm_neon.h>
|
||||||
|
#include "opus_types.h"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#if defined(__arm__) && !defined(__aarch64__) && (__ARM_ARCH < 8 || !defined(__clang__))
|
||||||
|
/* Emulate vcvtnq_s32_f32() for ARMv7 Neon. */
|
||||||
|
static OPUS_INLINE int32x4_t vcvtnq_s32_f32(float32x4_t x) {
|
||||||
|
return vrshrq_n_s32(vcvtq_n_s32_f32(x, 8), 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static OPUS_INLINE int16x8_t vpaddq_s16(int16x8_t a, int16x8_t b) {
|
||||||
|
return vcombine_s16(vpadd_s16(vget_low_s16(a), vget_high_s16(a)), vpadd_s16(vget_low_s16(b), vget_high_s16(b)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static OPUS_INLINE int16x8_t vmull_high_s8(int8x16_t a, int8x16_t b) {
|
||||||
|
return vmull_s8(vget_high_s8(a), vget_high_s8(b));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __ARM_FEATURE_FMA
|
||||||
|
/* If we can, force the compiler to use an FMA instruction rather than break
|
||||||
|
vmlaq_f32() into fmul/fadd. */
|
||||||
|
#define vmlaq_f32(a,b,c) vfmaq_f32(a,b,c)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LPCNET_TEST
|
||||||
|
static inline float32x4_t exp4_approx(float32x4_t x) {
|
||||||
|
int32x4_t i;
|
||||||
|
float32x4_t xf;
|
||||||
|
|
||||||
|
x = vmaxq_f32(vminq_f32(x, vdupq_n_f32(88.f)), vdupq_n_f32(-88.f));
|
||||||
|
|
||||||
|
/* express exp(x) as exp2(x/log(2)), add 127 for the exponent later */
|
||||||
|
x = vmlaq_f32(vdupq_n_f32(127.f), x, vdupq_n_f32(1.44269504f));
|
||||||
|
|
||||||
|
/* split into integer and fractional parts */
|
||||||
|
i = vcvtq_s32_f32(x);
|
||||||
|
xf = vcvtq_f32_s32(i);
|
||||||
|
x = vsubq_f32(x, xf);
|
||||||
|
|
||||||
|
float32x4_t K0 = vdupq_n_f32(0.99992522f);
|
||||||
|
float32x4_t K1 = vdupq_n_f32(0.69583354f);
|
||||||
|
float32x4_t K2 = vdupq_n_f32(0.22606716f);
|
||||||
|
float32x4_t K3 = vdupq_n_f32(0.078024523f);
|
||||||
|
float32x4_t Y = vmlaq_f32(K0, x, vmlaq_f32(K1, x, vmlaq_f32(K2, K3, x)));
|
||||||
|
|
||||||
|
/* compute 2^i */
|
||||||
|
float32x4_t exponent = vreinterpretq_f32_s32(vshlq_n_s32(i, 23));
|
||||||
|
|
||||||
|
Y = vmulq_f32(Y, exponent);
|
||||||
|
return Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline float32x4_t tanh4_approx(float32x4_t X)
|
||||||
|
{
|
||||||
|
const float32x4_t N0 = vdupq_n_f32(952.52801514f);
|
||||||
|
const float32x4_t N1 = vdupq_n_f32(96.39235687f);
|
||||||
|
const float32x4_t N2 = vdupq_n_f32(0.60863042f);
|
||||||
|
const float32x4_t D0 = vdupq_n_f32(952.72399902f);
|
||||||
|
const float32x4_t D1 = vdupq_n_f32(413.36801147f);
|
||||||
|
const float32x4_t D2 = vdupq_n_f32(11.88600922f);
|
||||||
|
const float32x4_t max_out = vdupq_n_f32(1.f);
|
||||||
|
const float32x4_t min_out = vdupq_n_f32(-1.f);
|
||||||
|
float32x4_t X2, num, den;
|
||||||
|
X2 = vmulq_f32(X, X);
|
||||||
|
num = vmlaq_f32(N0, X2, vmlaq_f32(N1, N2, X2));
|
||||||
|
den = vmlaq_f32(D0, X2, vmlaq_f32(D1, D2, X2));
|
||||||
|
num = vmulq_f32(num, X);
|
||||||
|
den = vrecpeq_f32(den);
|
||||||
|
num = vmulq_f32(num, den);
|
||||||
|
return vmaxq_f32(min_out, vminq_f32(max_out, num));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline float32x4_t sigmoid4_approx(float32x4_t X)
|
||||||
|
{
|
||||||
|
const float32x4_t N0 = vdupq_n_f32(238.13200378f);
|
||||||
|
const float32x4_t N1 = vdupq_n_f32(6.02452230f);
|
||||||
|
const float32x4_t N2 = vdupq_n_f32(0.00950985f);
|
||||||
|
const float32x4_t D0 = vdupq_n_f32(952.72399902f);
|
||||||
|
const float32x4_t D1 = vdupq_n_f32(103.34200287f);
|
||||||
|
const float32x4_t D2 = vdupq_n_f32(0.74287558f);
|
||||||
|
const float32x4_t half = vdupq_n_f32(0.5f);
|
||||||
|
const float32x4_t max_out = vdupq_n_f32(1.f);
|
||||||
|
const float32x4_t min_out = vdupq_n_f32(0.f);
|
||||||
|
float32x4_t X2, num, den;
|
||||||
|
X2 = vmulq_f32(X, X);
|
||||||
|
num = vmlaq_f32(N0, X2, vmlaq_f32(N1, N2, X2));
|
||||||
|
den = vmlaq_f32(D0, X2, vmlaq_f32(D1, D2, X2));
|
||||||
|
num = vmulq_f32(num, X);
|
||||||
|
den = vrecpeq_f32(den);
|
||||||
|
num = vmlaq_f32(half, num, den);
|
||||||
|
return vmaxq_f32(min_out, vminq_f32(max_out, num));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline float lpcnet_exp(float x)
|
||||||
|
{
|
||||||
|
float out[4];
|
||||||
|
float32x4_t X, Y;
|
||||||
|
X = vdupq_n_f32(x);
|
||||||
|
Y = exp4_approx(X);
|
||||||
|
vst1q_f32(out, Y);
|
||||||
|
return out[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline float tanh_approx(float x)
|
||||||
|
{
|
||||||
|
float out[4];
|
||||||
|
float32x4_t X, Y;
|
||||||
|
X = vdupq_n_f32(x);
|
||||||
|
Y = tanh4_approx(X);
|
||||||
|
vst1q_f32(out, Y);
|
||||||
|
return out[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline float sigmoid_approx(float x)
|
||||||
|
{
|
||||||
|
float out[4];
|
||||||
|
float32x4_t X, Y;
|
||||||
|
X = vdupq_n_f32(x);
|
||||||
|
Y = sigmoid4_approx(X);
|
||||||
|
vst1q_f32(out, Y);
|
||||||
|
return out[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void softmax(float *y, const float *x, int N)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i=0;i<N-3;i+=4)
|
||||||
|
{
|
||||||
|
float32x4_t X, Y;
|
||||||
|
X = vld1q_f32(&x[i]);
|
||||||
|
Y = exp4_approx(X);
|
||||||
|
vst1q_f32(&y[i], Y);
|
||||||
|
}
|
||||||
|
for (;i<N;i++)
|
||||||
|
y[i] = lpcnet_exp(x[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void vec_tanh(float *y, const float *x, int N)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i=0;i<N-3;i+=4)
|
||||||
|
{
|
||||||
|
float32x4_t X, Y;
|
||||||
|
X = vld1q_f32(&x[i]);
|
||||||
|
Y = tanh4_approx(X);
|
||||||
|
vst1q_f32(&y[i], Y);
|
||||||
|
}
|
||||||
|
for (;i<N;i++)
|
||||||
|
{
|
||||||
|
float ex2;
|
||||||
|
ex2 = lpcnet_exp(2*x[i]);
|
||||||
|
y[i] = (ex2-1)/(ex2+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void vec_sigmoid(float *y, const float *x, int N)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i=0;i<N-3;i+=4)
|
||||||
|
{
|
||||||
|
float32x4_t X, Y;
|
||||||
|
X = vld1q_f32(&x[i]);
|
||||||
|
Y = sigmoid4_approx(X);
|
||||||
|
vst1q_f32(&y[i], Y);
|
||||||
|
}
|
||||||
|
for (;i<N;i++)
|
||||||
|
{
|
||||||
|
float ex;
|
||||||
|
ex = lpcnet_exp(x[i]);
|
||||||
|
y[i] = (ex)/(ex+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline void sgemv16x1(float *out, const float *weights, int rows, int cols, int col_stride, const float *x)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
for (i=0;i<rows;i+=16)
|
||||||
|
{
|
||||||
|
float * restrict y = &out[i];
|
||||||
|
|
||||||
|
/* keep y[0..15] in registers for duration of inner loop */
|
||||||
|
|
||||||
|
float32x4_t y0_3 = vdupq_n_f32(0);
|
||||||
|
float32x4_t y4_7 = vdupq_n_f32(0);
|
||||||
|
float32x4_t y8_11 = vdupq_n_f32(0);
|
||||||
|
float32x4_t y12_15 = vdupq_n_f32(0);
|
||||||
|
|
||||||
|
for (j=0;j<cols;j++)
|
||||||
|
{
|
||||||
|
const float * restrict w;
|
||||||
|
float32x4_t wvec0_3, wvec4_7, wvec8_11, wvec12_15;
|
||||||
|
float32x4_t xj;
|
||||||
|
|
||||||
|
w = &weights[j*col_stride + i];
|
||||||
|
wvec0_3 = vld1q_f32(&w[0]);
|
||||||
|
wvec4_7 = vld1q_f32(&w[4]);
|
||||||
|
wvec8_11 = vld1q_f32(&w[8]);
|
||||||
|
wvec12_15 = vld1q_f32(&w[12]);
|
||||||
|
|
||||||
|
xj = vld1q_dup_f32(&x[j]);
|
||||||
|
|
||||||
|
y0_3 = vmlaq_f32(y0_3, wvec0_3, xj);
|
||||||
|
y4_7 = vmlaq_f32(y4_7, wvec4_7, xj);
|
||||||
|
y8_11 = vmlaq_f32(y8_11, wvec8_11, xj);
|
||||||
|
y12_15 = vmlaq_f32(y12_15, wvec12_15, xj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* save y[0..15] back to memory */
|
||||||
|
|
||||||
|
vst1q_f32(&y[0], y0_3);
|
||||||
|
vst1q_f32(&y[4], y4_7);
|
||||||
|
vst1q_f32(&y[8], y8_11);
|
||||||
|
vst1q_f32(&y[12], y12_15);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void sgemv8x1(float *out, const float *weights, int rows, int cols, int col_stride, const float *x)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
for (i=0;i<rows;i+=8)
|
||||||
|
{
|
||||||
|
float * restrict y = &out[i];
|
||||||
|
|
||||||
|
/* keep y[0..15] in registers for duration of inner loop */
|
||||||
|
|
||||||
|
float32x4_t y0_3 = vdupq_n_f32(0);
|
||||||
|
float32x4_t y4_7 = vdupq_n_f32(0);
|
||||||
|
|
||||||
|
for (j=0;j<cols;j++)
|
||||||
|
{
|
||||||
|
const float * restrict w;
|
||||||
|
float32x4_t wvec0_3, wvec4_7;
|
||||||
|
float32x4_t xj;
|
||||||
|
|
||||||
|
w = &weights[j*col_stride + i];
|
||||||
|
wvec0_3 = vld1q_f32(&w[0]);
|
||||||
|
wvec4_7 = vld1q_f32(&w[4]);
|
||||||
|
|
||||||
|
xj = vld1q_dup_f32(&x[j]);
|
||||||
|
|
||||||
|
y0_3 = vmlaq_f32(y0_3, wvec0_3, xj);
|
||||||
|
y4_7 = vmlaq_f32(y4_7, wvec4_7, xj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* save y[0..15] back to memory */
|
||||||
|
|
||||||
|
vst1q_f32(&y[0], y0_3);
|
||||||
|
vst1q_f32(&y[4], y4_7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void sgemv(float *out, const float *weights, int rows, int cols, int col_stride, const float *x)
|
||||||
|
{
|
||||||
|
if ((rows&0xf) == 0) sgemv16x1(out, weights, rows, cols, col_stride, x);
|
||||||
|
else if ((rows&0x7) == 0) sgemv8x1(out, weights, rows, cols, col_stride, x);
|
||||||
|
else {
|
||||||
|
int i, j;
|
||||||
|
for (i=0;i<rows;i++)
|
||||||
|
{
|
||||||
|
out[i] = 0;
|
||||||
|
for (j=0;j<cols;j++) out[i] += weights[j*col_stride + i]*x[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Temporarily use unoptimized version */
|
||||||
|
static inline void sparse_sgemv8x4(float *out, const float *w, const int *idx, int rows, const float *x)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
RNN_CLEAR(out, rows);
|
||||||
|
for (i=0;i<rows;i+=8)
|
||||||
|
{
|
||||||
|
int cols;
|
||||||
|
cols = *idx++;
|
||||||
|
for (j=0;j<cols;j++)
|
||||||
|
{
|
||||||
|
int pos;
|
||||||
|
float * restrict y;
|
||||||
|
float xj0, xj1, xj2, xj3;
|
||||||
|
pos = (*idx++);
|
||||||
|
xj0 = x[pos+0];
|
||||||
|
xj1 = x[pos+1];
|
||||||
|
xj2 = x[pos+2];
|
||||||
|
xj3 = x[pos+3];
|
||||||
|
y = &out[i];
|
||||||
|
y[0] += w[0]*xj0;
|
||||||
|
y[1] += w[1]*xj0;
|
||||||
|
y[2] += w[2]*xj0;
|
||||||
|
y[3] += w[3]*xj0;
|
||||||
|
y[4] += w[4]*xj0;
|
||||||
|
y[5] += w[5]*xj0;
|
||||||
|
y[6] += w[6]*xj0;
|
||||||
|
y[7] += w[7]*xj0;
|
||||||
|
|
||||||
|
y[0] += w[8]*xj1;
|
||||||
|
y[1] += w[9]*xj1;
|
||||||
|
y[2] += w[10]*xj1;
|
||||||
|
y[3] += w[11]*xj1;
|
||||||
|
y[4] += w[12]*xj1;
|
||||||
|
y[5] += w[13]*xj1;
|
||||||
|
y[6] += w[14]*xj1;
|
||||||
|
y[7] += w[15]*xj1;
|
||||||
|
|
||||||
|
y[0] += w[16]*xj2;
|
||||||
|
y[1] += w[17]*xj2;
|
||||||
|
y[2] += w[18]*xj2;
|
||||||
|
y[3] += w[19]*xj2;
|
||||||
|
y[4] += w[20]*xj2;
|
||||||
|
y[5] += w[21]*xj2;
|
||||||
|
y[6] += w[22]*xj2;
|
||||||
|
y[7] += w[23]*xj2;
|
||||||
|
|
||||||
|
y[0] += w[24]*xj3;
|
||||||
|
y[1] += w[25]*xj3;
|
||||||
|
y[2] += w[26]*xj3;
|
||||||
|
y[3] += w[27]*xj3;
|
||||||
|
y[4] += w[28]*xj3;
|
||||||
|
y[5] += w[29]*xj3;
|
||||||
|
y[6] += w[30]*xj3;
|
||||||
|
y[7] += w[31]*xj3;
|
||||||
|
w += 32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define SCALE (128.f*127.f)
|
||||||
|
#define SCALE_1 (1.f/128.f/127.f)
|
||||||
|
|
||||||
|
#define MAX_INPUTS 2048
|
||||||
|
#define MAX_OUTPUTS 8192
|
||||||
|
|
||||||
|
#if __ARM_FEATURE_DOTPROD
|
||||||
|
static inline int32x4_t vdotprod(int32x4_t acc, int8x16_t a, int8x16_t b) {
|
||||||
|
return vdotq_s32(acc, a, b);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static inline int32x4_t vdotprod(int32x4_t acc, int8x16_t a, int8x16_t b)
|
||||||
|
{
|
||||||
|
return vpadalq_s16(acc, vpaddq_s16(vmull_s8(vget_low_s8(a), vget_low_s8(b)), vmull_high_s8(a, b)));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline void cgemv8x4(float *_out, const opus_int8 *w, const float *scale, int rows, int cols, const float *_x)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
opus_int32 x_int[MAX_INPUTS/4];
|
||||||
|
opus_int8 *x = (opus_int8*) x_int;
|
||||||
|
const float32x4_t const127 = vdupq_n_f32(127.);
|
||||||
|
for (i=0;i<cols;i+=8) {
|
||||||
|
int32x4_t xi0, xi4;
|
||||||
|
int16x8_t x_short;
|
||||||
|
xi0 = vcvtnq_s32_f32(vmulq_f32(const127, vld1q_f32(&_x[i])));
|
||||||
|
xi4 = vcvtnq_s32_f32(vmulq_f32(const127, vld1q_f32(&_x[i+4])));
|
||||||
|
x_short = vcombine_s16(vmovn_s32(xi0), vmovn_s32(xi4));
|
||||||
|
vst1_s8(&x[i], vmovn_s16(x_short));
|
||||||
|
}
|
||||||
|
for (i=0;i<rows;i+=8)
|
||||||
|
{
|
||||||
|
int32x4_t acc0, acc1;
|
||||||
|
int32x4_t acc2, acc3;
|
||||||
|
acc0 = vdupq_n_s32(0);
|
||||||
|
acc1 = vdupq_n_s32(0);
|
||||||
|
acc2 = vdupq_n_s32(0);
|
||||||
|
acc3 = vdupq_n_s32(0);
|
||||||
|
j=0;
|
||||||
|
for (;j<cols-4;j+=8)
|
||||||
|
{
|
||||||
|
int8x16_t vw0, vw1, vw2, vw3, vx0, vx1;
|
||||||
|
vx0 = (int8x16_t)vld1q_dup_s32((int*)(void*)&x[j]);
|
||||||
|
vw0 = vld1q_s8(w);
|
||||||
|
vw1 = vld1q_s8(&w[16]);
|
||||||
|
acc0 = vdotprod(acc0, vw0, vx0);
|
||||||
|
acc1 = vdotprod(acc1, vw1, vx0);
|
||||||
|
vx1 = (int8x16_t)vld1q_dup_s32((int*)(void*)&x[j+4]);
|
||||||
|
vw2 = vld1q_s8(&w[32]);
|
||||||
|
vw3 = vld1q_s8(&w[48]);
|
||||||
|
acc2 = vdotprod(acc2, vw2, vx1);
|
||||||
|
acc3 = vdotprod(acc3, vw3, vx1);
|
||||||
|
w += 64;
|
||||||
|
}
|
||||||
|
acc0 = vaddq_s32(acc0, acc2);
|
||||||
|
acc1 = vaddq_s32(acc1, acc3);
|
||||||
|
for (;j<cols;j+=4)
|
||||||
|
{
|
||||||
|
int8x16_t vw0, vw1, vx;
|
||||||
|
vx = (int8x16_t)vld1q_dup_s32((int*)(void*)&x[j]);
|
||||||
|
vw0 = vld1q_s8(w);
|
||||||
|
vw1 = vld1q_s8(&w[16]);
|
||||||
|
acc0 = vdotprod(acc0, vw0, vx);
|
||||||
|
acc1 = vdotprod(acc1, vw1, vx);
|
||||||
|
w += 32;
|
||||||
|
}
|
||||||
|
vst1q_f32(&_out[i], vmulq_f32(vld1q_f32(&scale[i]), vcvtq_f32_s32(acc0)));
|
||||||
|
vst1q_f32(&_out[i+4], vmulq_f32(vld1q_f32(&scale[i+4]), vcvtq_f32_s32(acc1)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void sparse_cgemv8x4(float *_out, const opus_int8 *w, const int *idx, const float *scale, int rows, int cols, const float *_x)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
opus_int32 x_int[MAX_INPUTS/4];
|
||||||
|
opus_int8 *x = (opus_int8*) x_int;
|
||||||
|
const float32x4_t const127 = vdupq_n_f32(127.);
|
||||||
|
for (i=0;i<cols;i+=8) {
|
||||||
|
int32x4_t xi0, xi4;
|
||||||
|
int16x8_t x_short;
|
||||||
|
xi0 = vcvtnq_s32_f32(vmulq_f32(const127, vld1q_f32(&_x[i])));
|
||||||
|
xi4 = vcvtnq_s32_f32(vmulq_f32(const127, vld1q_f32(&_x[i+4])));
|
||||||
|
x_short = vcombine_s16(vmovn_s32(xi0), vmovn_s32(xi4));
|
||||||
|
vst1_s8(&x[i], vmovn_s16(x_short));
|
||||||
|
}
|
||||||
|
for (i=0;i<rows;i+=8)
|
||||||
|
{
|
||||||
|
int colblocks;
|
||||||
|
int32x4_t acc0, acc1;
|
||||||
|
acc0 = vdupq_n_s32(0);
|
||||||
|
acc1 = vdupq_n_s32(0);
|
||||||
|
colblocks = *idx++;
|
||||||
|
for (j=0;j<colblocks;j++)
|
||||||
|
{
|
||||||
|
int pos;
|
||||||
|
pos = (*idx++);
|
||||||
|
int8x16_t vw0, vw1, vx;
|
||||||
|
vx = (int8x16_t)vld1q_dup_s32((int*)(void*)&x[pos]);
|
||||||
|
vw0 = vld1q_s8(w);
|
||||||
|
vw1 = vld1q_s8(&w[16]);
|
||||||
|
acc0 = vdotprod(acc0, vw0, vx);
|
||||||
|
acc1 = vdotprod(acc1, vw1, vx);
|
||||||
|
w += 32;
|
||||||
|
}
|
||||||
|
vst1q_f32(&_out[i], vmulq_f32(vld1q_f32(&scale[i]), vcvtq_f32_s32(acc0)));
|
||||||
|
vst1q_f32(&_out[i+4], vmulq_f32(vld1q_f32(&scale[i+4]), vcvtq_f32_s32(acc1)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
85
third_party/rnnoise/src/x86/dnn_x86.h
vendored
Normal file
85
third_party/rnnoise/src/x86/dnn_x86.h
vendored
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
/* Copyright (c) 2011-2019 Mozilla
|
||||||
|
2023 Amazon */
|
||||||
|
/*
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
- Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||||||
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DNN_X86_H
|
||||||
|
#define DNN_X86_H
|
||||||
|
|
||||||
|
#include "cpu_support.h"
|
||||||
|
#include "opus_types.h"
|
||||||
|
|
||||||
|
void compute_linear_sse4_1(const LinearLayer *linear, float *out, const float *in);
|
||||||
|
void compute_activation_sse4_1(float *output, const float *input, int N, int activation);
|
||||||
|
void compute_conv2d_sse4_1(const Conv2dLayer *conv, float *out, float *mem, const float *in, int height, int hstride, int activation);
|
||||||
|
|
||||||
|
void compute_linear_avx2(const LinearLayer *linear, float *out, const float *in);
|
||||||
|
void compute_activation_avx2(float *output, const float *input, int N, int activation);
|
||||||
|
void compute_conv2d_avx2(const Conv2dLayer *conv, float *out, float *mem, const float *in, int height, int hstride, int activation);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef RNN_ENABLE_X86_RTCD
|
||||||
|
|
||||||
|
extern void (*const RNN_COMPUTE_LINEAR_IMPL[OPUS_ARCHMASK + 1])(
|
||||||
|
const LinearLayer *linear,
|
||||||
|
float *out,
|
||||||
|
const float *in
|
||||||
|
);
|
||||||
|
#define OVERRIDE_COMPUTE_LINEAR
|
||||||
|
#define compute_linear(linear, out, in, arch) \
|
||||||
|
((*RNN_COMPUTE_LINEAR_IMPL[(arch) & OPUS_ARCHMASK])(linear, out, in))
|
||||||
|
|
||||||
|
|
||||||
|
extern void (*const RNN_COMPUTE_ACTIVATION_IMPL[OPUS_ARCHMASK + 1])(
|
||||||
|
float *output,
|
||||||
|
const float *input,
|
||||||
|
int N,
|
||||||
|
int activation
|
||||||
|
);
|
||||||
|
#define OVERRIDE_COMPUTE_ACTIVATION
|
||||||
|
#define compute_activation(output, input, N, activation, arch) \
|
||||||
|
((*RNN_COMPUTE_ACTIVATION_IMPL[(arch) & OPUS_ARCHMASK])(output, input, N, activation))
|
||||||
|
|
||||||
|
|
||||||
|
extern void (*const RNN_COMPUTE_CONV2D_IMPL[OPUS_ARCHMASK + 1])(
|
||||||
|
const Conv2dLayer *conv,
|
||||||
|
float *out,
|
||||||
|
float *mem,
|
||||||
|
const float *in,
|
||||||
|
int height,
|
||||||
|
int hstride,
|
||||||
|
int activation
|
||||||
|
);
|
||||||
|
#define OVERRIDE_COMPUTE_CONV2D
|
||||||
|
#define compute_conv2d(conv, out, mem, in, height, hstride, activation, arch) \
|
||||||
|
((*RNN_COMPUTE_CONV2D_IMPL[(arch) & OPUS_ARCHMASK])(conv, out, mem, in, height, hstride, activation))
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* DNN_X86_H */
|
||||||
47
third_party/rnnoise/src/x86/x86_arch_macros.h
vendored
Normal file
47
third_party/rnnoise/src/x86/x86_arch_macros.h
vendored
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/* Copyright (c) 2023 Amazon */
|
||||||
|
/*
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
- Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||||||
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
|
||||||
|
# ifdef OPUS_X86_MAY_HAVE_SSE
|
||||||
|
# ifndef __SSE__
|
||||||
|
# define __SSE__
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifdef OPUS_X86_MAY_HAVE_SSE2
|
||||||
|
# ifndef __SSE2__
|
||||||
|
# define __SSE2__
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifdef OPUS_X86_MAY_HAVE_SSE4_1
|
||||||
|
# ifndef __SSE4_1__
|
||||||
|
# define __SSE4_1__
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#endif
|
||||||
88
third_party/rnnoise/src/x86/x86cpu.h
vendored
Normal file
88
third_party/rnnoise/src/x86/x86cpu.h
vendored
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
/* Copyright (c) 2014, Cisco Systems, INC
|
||||||
|
Written by XiangMingZhu WeiZhou MinPeng YanWang
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
- Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||||
|
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(X86CPU_H)
|
||||||
|
# define X86CPU_H
|
||||||
|
|
||||||
|
# define MAY_HAVE_SSE4_1(name) name ## _sse4_1
|
||||||
|
|
||||||
|
# define MAY_HAVE_AVX2(name) name ## _avx2
|
||||||
|
|
||||||
|
# ifdef RNN_ENABLE_X86_RTCD
|
||||||
|
int opus_select_arch(void);
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if defined(__SSE2__)
|
||||||
|
# include "common.h"
|
||||||
|
|
||||||
|
/*MOVD should not impose any alignment restrictions, but the C standard does,
|
||||||
|
and UBSan will report errors if we actually make unaligned accesses.
|
||||||
|
Use this to work around those restrictions (which should hopefully all get
|
||||||
|
optimized to a single MOVD instruction).
|
||||||
|
GCC implemented _mm_loadu_si32() since GCC 11; HOWEVER, there is a bug!
|
||||||
|
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99754
|
||||||
|
LLVM implemented _mm_loadu_si32() since Clang 8.0, however the
|
||||||
|
__clang_major__ version number macro is unreliable, as vendors
|
||||||
|
(specifically, Apple) will use different numbering schemes than upstream.
|
||||||
|
Clang's advice is "use feature detection", but they do not provide feature
|
||||||
|
detection support for specific SIMD functions.
|
||||||
|
We follow the approach from the SIMDe project and instead detect unrelated
|
||||||
|
features that should be available in the version we want (see
|
||||||
|
<https://github.com/simd-everywhere/simde/blob/master/simde/simde-detect-clang.h>).*/
|
||||||
|
# if defined(__clang__)
|
||||||
|
# if __has_warning("-Wextra-semi-stmt") || \
|
||||||
|
__has_builtin(__builtin_rotateleft32)
|
||||||
|
# define OPUS_CLANG_8 (1)
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
# if !defined(_MSC_VER) && !OPUS_GNUC_PREREQ(11,3) && !defined(OPUS_CLANG_8)
|
||||||
|
# include <string.h>
|
||||||
|
# include <emmintrin.h>
|
||||||
|
|
||||||
|
# ifdef _mm_loadu_si32
|
||||||
|
# undef _mm_loadu_si32
|
||||||
|
# endif
|
||||||
|
# define _mm_loadu_si32 WORKAROUND_mm_loadu_si32
|
||||||
|
static inline __m128i WORKAROUND_mm_loadu_si32(void const* mem_addr) {
|
||||||
|
int val;
|
||||||
|
memcpy(&val, mem_addr, sizeof(val));
|
||||||
|
return _mm_cvtsi32_si128(val);
|
||||||
|
}
|
||||||
|
# elif defined(_MSC_VER)
|
||||||
|
/* MSVC needs this for _mm_loadu_si32 */
|
||||||
|
# include <immintrin.h>
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# define OP_CVTEPI8_EPI32_M32(x) \
|
||||||
|
(_mm_cvtepi8_epi32(_mm_loadu_si32(x)))
|
||||||
|
|
||||||
|
# define OP_CVTEPI16_EPI32_M64(x) \
|
||||||
|
(_mm_cvtepi16_epi32(_mm_loadl_epi64((__m128i *)(void*)(x))))
|
||||||
|
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -14,5 +14,6 @@
|
|||||||
{ "name": "opus", "$why": "voice codec (libopus) — docs/voice.md — M2" },
|
{ "name": "opus", "$why": "voice codec (libopus) — docs/voice.md — M2" },
|
||||||
{ "name": "miniaudio", "$why": "cross-platform capture/playback — docs/tech-stack.md — M2" }
|
{ "name": "miniaudio", "$why": "cross-platform capture/playback — docs/tech-stack.md — M2" }
|
||||||
],
|
],
|
||||||
"$license-note": "All of the above are permissive (BSD/MIT/ISC/Apache-2.0/public-domain). No GPL/LGPL — see docs/tech-stack.md §5."
|
"$license-note": "All of the above are permissive (BSD/MIT/ISC/Apache-2.0/public-domain). No GPL/LGPL — see docs/tech-stack.md §5.",
|
||||||
|
"$vendored-note": "RNNoise (noise suppression) is NOT a vcpkg dep — its port is !windows !arm — so it is vendored in third_party/rnnoise/ (BSD-3 + CC0). See third_party/README.md and docs/voice.md §10."
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user