voice_audio_multi/tests/audio/stft_parity_dump.cpp
Fabio c36510c21e
Some checks failed
Linux Build / Linux cpu (push) Has been cancelled
Linux Build / Linux cpu-clang (push) Has been cancelled
Linux Build / Linux vulkan (push) Has been cancelled
mac-build / macOS CPU (push) Has been cancelled
Nix Build / Nix (cpu) (push) Has been cancelled
Nix Build / Nix (vulkan) (push) Has been cancelled
windows-build / Windows CPU (push) Has been cancelled
Initial import: audio.cpp with Orange Pi documentation
2026-11-04 19:05:22 +01:00

131 lines
4.6 KiB
C++

#include "engine/framework/audio/dsp.h"
#include "engine/framework/audio/wav_reader.h"
#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <cmath>
#include <stdexcept>
#include <string>
#include <vector>
namespace {
void write_f32_file(const std::filesystem::path & path, const std::vector<float> & values) {
std::ofstream out(path, std::ios::binary);
if (!out) {
throw std::runtime_error("failed to open output file: " + path.string());
}
out.write(reinterpret_cast<const char *>(values.data()), static_cast<std::streamsize>(values.size() * sizeof(float)));
if (!out) {
throw std::runtime_error("failed to write output file: " + path.string());
}
}
void write_i64_file(const std::filesystem::path & path, const std::vector<int64_t> & values) {
std::ofstream out(path, std::ios::binary);
if (!out) {
throw std::runtime_error("failed to open output file: " + path.string());
}
out.write(reinterpret_cast<const char *>(values.data()), static_cast<std::streamsize>(values.size() * sizeof(int64_t)));
if (!out) {
throw std::runtime_error("failed to write output file: " + path.string());
}
}
} // namespace
int main(int argc, char ** argv) {
if (argc < 5) {
std::cerr << "Usage: stft_parity_dump <wav> <kind:stft> <out_f32> <out_shape_i64>"
" [--preemphasis VALUE] [--n-fft N] [--hop-length N] [--win-length N] [--pad-mode constant|reflect]\n";
return 1;
}
const std::filesystem::path wav_path(argv[1]);
const std::string kind(argv[2]);
const std::filesystem::path out_f32(argv[3]);
const std::filesystem::path out_shape(argv[4]);
float preemphasis = 0.0f;
int64_t n_fft = 512;
int64_t hop_length = 160;
int64_t win_length = 400;
engine::audio::STFTPadMode pad_mode = engine::audio::STFTPadMode::Constant;
for (int i = 5; i < argc; i += 2) {
if (i + 1 >= argc) {
throw std::runtime_error("missing value for trailing option");
}
const std::string option(argv[i]);
const std::string value(argv[i + 1]);
if (option == "--preemphasis") {
preemphasis = std::strtof(value.c_str(), nullptr);
} else if (option == "--n-fft") {
n_fft = std::strtoll(value.c_str(), nullptr, 10);
} else if (option == "--hop-length") {
hop_length = std::strtoll(value.c_str(), nullptr, 10);
} else if (option == "--win-length") {
win_length = std::strtoll(value.c_str(), nullptr, 10);
} else if (option == "--pad-mode") {
if (value == "constant") {
pad_mode = engine::audio::STFTPadMode::Constant;
} else if (value == "reflect") {
pad_mode = engine::audio::STFTPadMode::Reflect;
} else {
throw std::runtime_error("pad-mode must be 'constant' or 'reflect'");
}
} else {
throw std::runtime_error("unknown option: " + option);
}
}
auto wav = engine::audio::read_wav_f32(wav_path);
if (wav.channels != 1) {
throw std::runtime_error("stft_parity_dump requires mono WAV");
}
if (preemphasis != 0.0f && !wav.samples.empty()) {
for (size_t i = wav.samples.size() - 1; i >= 1; --i) {
wav.samples[i] = wav.samples[i] - preemphasis * wav.samples[i - 1];
}
}
const engine::audio::STFTConfig config{
n_fft,
hop_length,
win_length,
true,
pad_mode,
};
std::vector<float> window(static_cast<size_t>(config.win_length), 0.0f);
if (config.win_length == 1) {
window[0] = 1.0f;
} else {
constexpr long double kPi = 3.14159265358979323846264338327950288L;
for (int64_t i = 0; i < config.win_length; ++i) {
window[static_cast<size_t>(i)] =
0.5f - 0.5f * std::cos(2.0L * kPi * static_cast<long double>(i) /
static_cast<long double>(config.win_length - 1));
}
}
engine::audio::AudioTensor result;
if (kind == "stft") {
result = engine::audio::STFT().compute_complex(
wav.samples,
window,
1,
static_cast<int64_t>(wav.samples.size()),
config);
} else {
throw std::runtime_error("kind must be 'stft'");
}
write_f32_file(out_f32, result.values);
write_i64_file(out_shape, result.shape);
std::cout << "wrote " << result.values.size() << " floats\n";
std::cout << "preemphasis " << preemphasis << "\n";
return 0;
}