Files
wehub-resource-sync 426e9eeabd
Voice Workbench / headless workbench (mocked backends) (push) Has been cancelled
Voice Workbench / real acoustic lane (nightly, provisioned only) (push) Has been cancelled
ci / test (push) Has been cancelled
ci / lint-and-format (push) Has been cancelled
ci / build (push) Has been cancelled
ci / dev-startup (push) Has been cancelled
gitleaks / gitleaks (push) Has been cancelled
Markdown Links / Relative Markdown Links (push) Has been cancelled
Quality (Extended) / Homepage Build (PR smoke) (push) Has been cancelled
Quality (Extended) / Comment-only diff guard (push) Has been cancelled
Quality (Extended) / Format + Type Safety Ratchet (push) Has been cancelled
Quality (Extended) / Develop Gate (secret scan + UI determinism) (push) Has been cancelled
Quality (Extended) / Develop Gate (lint) (push) Has been cancelled
Chat shell gestures / Chat shell gesture + parity e2e (push) Has been cancelled
Cloud Gateway Discord / Test (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx @biomejs/biome check packages/lifeops-bench/src, benchmark-lint) (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx vitest run --config packages/lifeops-bench/vitest.config.ts --root packages/lifeops-bench --passWithNoTests, benchmark-tests) (push) Has been cancelled
Build Agent Image / build-and-push (push) Has been cancelled
Dev Smoke / bun run dev onboarding chat (push) Has been cancelled
Dev Smoke / Vite HMR dependency-level smoke (push) Has been cancelled
Electrobun Submodule Guard / electrobun gitlink is fetchable (push) Has been cancelled
Publish @elizaos/example-code / check_npm (push) Has been cancelled
Publish @elizaos/example-code / publish_npm (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / verify_version (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / publish_npm (push) Has been cancelled
Sandbox Live Smoke / Sandbox live smoke (push) Has been cancelled
Snap Build & Test / Build Snap (amd64) (push) Has been cancelled
Snap Build & Test / Build Snap (arm64) (push) Has been cancelled
Test Packaging / elizaos CLI global-install smoke (node + bun) (push) Has been cancelled
Cloud Gateway Webhook / Test (push) Has been cancelled
Cloud Tests / lint-and-types (push) Has been cancelled
Cloud Tests / unit-tests (push) Has been cancelled
Cloud Tests / integration-tests (push) Has been cancelled
Cloud Tests / e2e-tests (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Apps Worker (Product 2) / Determine environment (push) Has been cancelled
Deploy Apps Worker (Product 2) / Deploy apps worker to apps-control host (${{ needs.determine-env.outputs.environment }}) (push) Has been cancelled
Deploy Eliza Provisioning Worker / Determine environment (push) Has been cancelled
Deploy Eliza Provisioning Worker / Deploy worker to Hetzner host (${{ needs.determine-env.outputs.environment }} @ ${{ needs.determine-env.outputs.deployment_sha }}) (push) Has been cancelled
Dev Smoke / Classify changed paths (push) Has been cancelled
supply-chain / sbom (push) Has been cancelled
supply-chain / vulnerability-scan (push) Has been cancelled
Build, Push & Deploy to Phala Cloud / build-and-push (push) Has been cancelled
Test Packaging / Validate Packaging Configs (push) Has been cancelled
Test Packaging / Build & Test PyPI Package (push) Has been cancelled
Test Packaging / PyPI on Python ${{ matrix.python }} (push) Has been cancelled
Test Packaging / Pack & Test JS Tarballs (push) Has been cancelled
UI Fixture E2E / ui-fixture-e2e (push) Has been cancelled
UI Fixture E2E / fixture-e2e (push) Has been cancelled
UI Story Gate / story-gate (push) Has been cancelled
vault-ci / test (macos-latest) (push) Has been cancelled
vault-ci / test (ubuntu-latest) (push) Has been cancelled
vault-ci / test (windows-latest) (push) Has been cancelled
vault-ci / app-core wiring tests (push) Has been cancelled
verify-patches / verify patches/CHECKSUMS.sha256 (push) Has been cancelled
Voice Benchmark Smoke / voice-emotion fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voiceagentbench fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench-quality unit smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench TypeScript unit (no audio) (push) Has been cancelled
Voice Benchmark Smoke / voice bench smoke summary (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/app-core test bun run --cwd packages/elizaos test bun run --cwd packages/cloud/shared test], app-and-cli) (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/scenario-runner test bun run --cwd packages/vault test bun run --cwd packages/security test bun run --cwd plugins/plugin-coding-tools test], framework-packages) (push) Has been cancelled
Windows CI / windows ([bun run --cwd plugins/plugin-elizacloud test bun run --cwd plugins/plugin-discord test bun run --cwd plugins/plugin-anthropic test bun run --cwd plugins/plugin-openai test bun run --cwd plugins/plugin-app-control test bun run --cwd plugins/pl… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run build --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/agent --concurrency=4 node packages/scripts/run-bash-linux-only.mjs scripts/verify-riscv64-buildpaths.sh node packages/scripts/run… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run typecheck --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/cloud-shared --concurrency=4 bun run --cwd packages/core test bun run --cwd packages/shared test], core-runtime, 75) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:43:05 +08:00

276 lines
9.8 KiB
C++

// SPDX-License-Identifier: MIT
//
// istft-verify.cpp — Verification harness for GGML_OP_ISTFT.
//
// Generates 10 random (n_fft, hop_length, win_length, T) test cases,
// computes the CPU reference output using the eliza_kokoro::istft_hann
// reference implementation, and compares it against GGML dispatch results.
//
// Run:
// ./istft-verify [--backend cpu|vulkan|cuda] [--tol 1e-3] [--seed N]
//
// Exits 0 on PASS, 1 on any FAIL.
#define _POSIX_C_SOURCE 199309L
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <string>
#include <vector>
#include <random>
#include <algorithm>
// ---------------------------------------------------------------------------
// Inline CPU reference iSTFT (matches kokoro-istft.cpp exactly, no shared
// header dependency so this binary can build stand-alone).
// ---------------------------------------------------------------------------
static std::vector<float> hann_window_ref(int n) {
std::vector<float> w((size_t) n);
const double sc = 2.0 * 3.14159265358979323846 / (double) n;
for (int i = 0; i < n; ++i)
w[(size_t) i] = (float)(0.5 - 0.5 * std::cos(sc * (double) i));
return w;
}
static void irdft_frame_ref(const float * re, const float * im, int n_fft, float * out) {
const int F = n_fft / 2 + 1;
const double inv_n = 1.0 / (double) n_fft;
const double pi2 = 2.0 * 3.14159265358979323846;
for (int t = 0; t < n_fft; ++t) {
double acc = re[0];
if ((n_fft & 1) == 0) {
const double sign = (t & 1) ? -1.0 : 1.0;
acc += sign * re[F - 1];
}
const int ie = F - ((n_fft & 1) == 0 ? 1 : 0);
for (int f = 1; f < ie; ++f) {
const double angle = pi2 * (double) f * (double) t * inv_n;
acc += 2.0 * (re[f] * std::cos(angle) - im[f] * std::sin(angle));
}
out[t] = (float)(acc * inv_n);
}
}
static std::vector<float> istft_ref(
const std::vector<float> & mag,
const std::vector<float> & phase,
int n_fft, int hop_length, int win_length, int n_frames) {
const int F = n_fft / 2 + 1;
const int n_out = (n_frames - 1) * hop_length + win_length;
std::vector<float> out((size_t) n_out, 0.0f);
std::vector<float> norm((size_t) n_out, 0.0f);
auto window = hann_window_ref(win_length);
std::vector<float> re((size_t) F), im((size_t) F), frame((size_t) n_fft);
for (int t = 0; t < n_frames; ++t) {
for (int f = 0; f < F; ++f) {
const float m = mag [(size_t)(f * n_frames + t)];
const float p = phase[(size_t)(f * n_frames + t)];
re[(size_t) f] = m * std::cos(p);
im[(size_t) f] = m * std::sin(p);
}
irdft_frame_ref(re.data(), im.data(), n_fft, frame.data());
const int off = t * hop_length;
for (int k = 0; k < win_length; ++k) {
const int idx = off + k;
if (idx >= n_out) break;
const float w = window[(size_t) k];
out [(size_t) idx] += frame[(size_t)(k % n_fft)] * w;
norm[(size_t) idx] += w * w;
}
}
for (int i = 0; i < n_out; ++i)
if (norm[(size_t) i] > 1e-8f)
out[(size_t) i] /= norm[(size_t) i];
return out;
}
// ---------------------------------------------------------------------------
// GGML path
// ---------------------------------------------------------------------------
#include "ggml.h"
#include "ggml-alloc.h"
#include "ggml-backend.h"
#include "ggml-cpu.h"
#ifdef GGML_USE_VULKAN
# include "ggml-vulkan.h"
#endif
#ifdef GGML_USE_CUDA
# include "ggml-cuda.h"
#endif
static std::vector<float> istft_ggml(
ggml_backend_t backend,
const std::vector<float> & mag,
const std::vector<float> & phase,
int n_fft, int hop_length, int win_length, int n_frames,
bool & supported_out) {
const int F = n_fft / 2 + 1;
const int n_out = (n_frames - 1) * hop_length + win_length;
supported_out = false;
ggml_init_params ip = {
/*.mem_size =*/ 16 * 1024 * 1024,
/*.mem_buffer =*/ nullptr,
/*.no_alloc =*/ true,
};
ggml_context * gctx = ggml_init(ip);
if (!gctx) return {};
const int64_t ne_mp[4] = { (int64_t) n_frames, (int64_t) F, 2, 1 };
ggml_tensor * mp = ggml_new_tensor(gctx, GGML_TYPE_F32, 4, ne_mp);
ggml_tensor * pcm = ggml_istft(gctx, mp, nullptr, n_fft, hop_length, win_length);
ggml_cgraph * gf = ggml_new_graph_custom(gctx, 64, false);
ggml_build_forward_expand(gf, pcm);
ggml_gallocr_t alloc = ggml_gallocr_new(ggml_backend_get_default_buffer_type(backend));
if (!alloc) { ggml_free(gctx); return {}; }
if (!ggml_gallocr_alloc_graph(alloc, gf)) {
ggml_gallocr_free(alloc);
ggml_free(gctx);
return {};
}
// Pack mag/phase into [T, F, 2] flat.
const size_t ch_stride = (size_t) F * (size_t) n_frames;
std::vector<float> mp_data(2 * ch_stride);
for (int f = 0; f < F; ++f)
for (int t = 0; t < n_frames; ++t) {
mp_data[ f * n_frames + t] = mag [(size_t)(f * n_frames + t)];
mp_data[ch_stride + f * n_frames + t] = phase[(size_t)(f * n_frames + t)];
}
ggml_backend_tensor_set(mp, mp_data.data(), 0, mp_data.size() * sizeof(float));
if (!ggml_backend_supports_op(backend, pcm)) {
ggml_gallocr_free(alloc);
ggml_free(gctx);
return {};
}
supported_out = true;
ggml_backend_graph_compute(backend, gf);
std::vector<float> result((size_t) n_out);
ggml_backend_tensor_get(pcm, result.data(), 0, (size_t) n_out * sizeof(float));
ggml_gallocr_free(alloc);
ggml_free(gctx);
return result;
}
// ---------------------------------------------------------------------------
// Main
// ---------------------------------------------------------------------------
int main(int argc, char ** argv) {
float tol = 1e-3f;
unsigned seed = (unsigned) std::time(nullptr);
std::string backend_name = "cpu";
for (int i = 1; i < argc; ++i) {
if (strcmp(argv[i], "--backend") == 0 && i + 1 < argc) {
backend_name = argv[++i];
} else if (strcmp(argv[i], "--tol") == 0 && i + 1 < argc) {
tol = (float) std::atof(argv[++i]);
} else if (strcmp(argv[i], "--seed") == 0 && i + 1 < argc) {
seed = (unsigned) std::atoi(argv[++i]);
}
}
printf("istft-verify: backend=%s tol=%.2e seed=%u\n",
backend_name.c_str(), (double) tol, seed);
// Select backend.
ggml_backend_t backend = nullptr;
#ifdef GGML_USE_CUDA
if (backend_name == "cuda") {
backend = ggml_backend_cuda_init(0);
if (!backend) { fprintf(stderr, "CUDA backend unavailable\n"); return 1; }
}
#endif
#ifdef GGML_USE_VULKAN
if (backend_name == "vulkan") {
backend = ggml_backend_vk_init(0);
if (!backend) { fprintf(stderr, "Vulkan backend unavailable\n"); return 1; }
}
#endif
if (!backend) {
if (backend_name != "cpu") {
fprintf(stderr, "Warning: %s backend not compiled in, falling back to CPU\n",
backend_name.c_str());
}
backend = ggml_backend_cpu_init();
}
// Test cases: 10 random (n_fft, hop, win, T) configurations.
// n_fft in {8, 16, 20, 32, 64}; hop = n_fft/4; win = n_fft; T in [10, 50].
std::mt19937 rng(seed);
std::uniform_int_distribution<int> fft_dist(0, 4);
std::uniform_int_distribution<int> T_dist(10, 50);
std::uniform_real_distribution<float> val_dist(0.0f, 1.0f);
std::uniform_real_distribution<float> phase_dist(-3.14159f, 3.14159f);
const int nfft_choices[] = { 8, 16, 20, 32, 64 };
int n_pass = 0, n_fail = 0, n_skip = 0;
for (int tc = 0; tc < 10; ++tc) {
const int n_fft = nfft_choices[fft_dist(rng)];
const int hop_length = n_fft / 4;
const int win_length = n_fft;
const int n_frames = T_dist(rng);
const int F = n_fft / 2 + 1;
const int n_out = (n_frames - 1) * hop_length + win_length;
// Random magnitude + phase.
std::vector<float> mag ((size_t) F * n_frames);
std::vector<float> phase((size_t) F * n_frames);
for (auto & v : mag) v = val_dist(rng);
for (auto & v : phase) v = phase_dist(rng);
// CPU reference.
auto ref = istft_ref(mag, phase, n_fft, hop_length, win_length, n_frames);
// GGML dispatch.
bool supported = false;
auto got = istft_ggml(backend, mag, phase, n_fft, hop_length, win_length,
n_frames, supported);
if (!supported) {
printf(" case %2d: n_fft=%d hop=%d win=%d T=%d n_out=%d → SKIP (op not supported)\n",
tc, n_fft, hop_length, win_length, n_frames, n_out);
++n_skip;
continue;
}
if (got.size() != ref.size()) {
printf(" case %2d: n_fft=%d hop=%d win=%d T=%d → FAIL (size mismatch %zu vs %zu)\n",
tc, n_fft, hop_length, win_length, n_frames, got.size(), ref.size());
++n_fail;
continue;
}
float max_err = 0.0f;
for (size_t i = 0; i < ref.size(); ++i)
max_err = std::max(max_err, std::fabs(got[i] - ref[i]));
if (max_err <= tol) {
printf(" case %2d: n_fft=%d hop=%d win=%d T=%d n_out=%d → PASS (max_err=%.2e)\n",
tc, n_fft, hop_length, win_length, n_frames, n_out, (double) max_err);
++n_pass;
} else {
printf(" case %2d: n_fft=%d hop=%d win=%d T=%d n_out=%d → FAIL (max_err=%.2e > tol=%.2e)\n",
tc, n_fft, hop_length, win_length, n_frames, n_out, (double) max_err, (double) tol);
++n_fail;
}
}
ggml_backend_free(backend);
printf("\nSummary: %d PASS, %d FAIL, %d SKIP\n", n_pass, n_fail, n_skip);
return (n_fail > 0) ? 1 : 0;
}