当前位置: 首页 > news >正文

cpp实现音频重采样8k->16k及16k->8k

static int convert_8khz_to_16khz(void* dst_buf, void* src_buf, int src_size) {short* in = static_cast<short*>(src_buf);short* out = static_cast<short*>(dst_buf);int in_samples = src_size / sizeof(short);// 边界处理:前两个样本out[0] = in[0];out[1] = static_cast<short>(0.75f * in[0] + 0.25f * in[1]);// 主处理循环(使用三次Hermite插值)for (int i = 1; i < in_samples - 2; ++i) {// 原始样本点(应用抗混叠滤波)out[i*2] = static_cast<short>(0.1f * in[i-1] + 0.8f * in[i] + 0.1f * in[i+1]);// 插值点(三次Hermite插值)float t = 0.5f; // 中间位置float y0 = in[i-1], y1 = in[i], y2 = in[i+1], y3 = in[i+2];float a0 = y3 - y2 - y0 + y1;float a1 = y0 - y1 - a0;float a2 = y2 - y0;float a3 = y1;float interpolated = a0*t*t*t + a1*t*t + a2*t + a3;out[i*2 + 1] = static_cast<short>(interpolated);}// 边界处理:最后两个样本out[(in_samples-2)*2] = in[in_samples-2];out[(in_samples-2)*2 + 1] = static_cast<short>(0.25f * in[in_samples-2] + 0.75f * in[in_samples-1]);out[(in_samples-1)*2] = in[in_samples-1];out[(in_samples-1)*2 + 1] = in[in_samples-1];return src_size * 2;
}// 16kHz -> 8kHz 高质量降采样
static int convert_16khz_to_8khz(void* dst_buf, const void* src_buf, int src_size) {short* in = static_cast<short*>(const_cast<void*>(src_buf));short* out = static_cast<short*>(dst_buf);int in_samples = src_size / sizeof(short);// 边界处理out[0] = static_cast<short>(0.8f * in[0] + 0.2f * in[1]);// 主处理循环(带抗混叠滤波的降采样)for (int i = 1; i < in_samples / 2 - 1; ++i) {out[i] = static_cast<short>(0.1f * in[i*2-1] + 0.8f * in[i*2] + 0.1f * in[i*2+1]);}// 边界处理out[in_samples/2 - 1] = static_cast<short>(0.2f * in[in_samples-2] + 0.8f * in[in_samples-1]);return src_size / 2;
}

完整代码

#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <windows.h>// 获取当前可执行文件所在目录
std::string GetExeDirectory() {char path[MAX_PATH];GetModuleFileNameA(NULL, path, MAX_PATH);std::string exePath(path);size_t lastSlash = exePath.find_last_of("\\/");return exePath.substr(0, lastSlash + 1);
}// 获取项目根目录
std::string GetProjectRoot() {std::string exeDir = GetExeDirectory();size_t debugPos = exeDir.find("cmake-build-debug");if (debugPos != std::string::npos) {return exeDir.substr(0, debugPos);}return exeDir;
}// 读取PCM文件
std::vector<short> ReadPCMFile(const std::string &filename) {std::ifstream file(filename, std::ios::binary | std::ios::ate);if (!file) {throw std::runtime_error("无法打开文件: " + filename);}std::streamsize size = file.tellg();file.seekg(0, std::ios::beg);if (size % sizeof(short) != 0) {throw std::runtime_error("文件大小不是16-bit PCM的整数倍");}std::vector<short> buffer(size / sizeof(short));if (!file.read(reinterpret_cast<char *>(buffer.data()), size)) {throw std::runtime_error("读取文件失败");}return buffer;
}// 写入PCM文件
void WritePCMFile(const std::string &filename, const std::vector<short> &data) {std::ofstream file(filename, std::ios::binary);if (!file) {throw std::runtime_error("无法创建文件: " + filename);}file.write(reinterpret_cast<const char *>(data.data()), data.size() * sizeof(short));
}static int convert_8khz_to_16khz(void *dst_buf, void *src_buf, int src_size) {short *in = static_cast<short *>(src_buf);short *out = static_cast<short *>(dst_buf);int in_samples = src_size / sizeof(short);// 边界处理:前两个样本out[0] = in[0];out[1] = static_cast<short>(0.75f * in[0] + 0.25f * in[1]);// 主处理循环(使用三次Hermite插值)for (int i = 1; i < in_samples - 2; ++i) {// 原始样本点(应用抗混叠滤波)out[i * 2] = static_cast<short>(0.1f * in[i - 1] + 0.8f * in[i] + 0.1f * in[i + 1]);// 插值点(三次Hermite插值)float t = 0.5f; // 中间位置float y0 = in[i - 1], y1 = in[i], y2 = in[i + 1], y3 = in[i + 2];float a0 = y3 - y2 - y0 + y1;float a1 = y0 - y1 - a0;float a2 = y2 - y0;float a3 = y1;float interpolated = a0 * t * t * t + a1 * t * t + a2 * t + a3;out[i * 2 + 1] = static_cast<short>(interpolated);}// 边界处理:最后两个样本out[(in_samples - 2) * 2] = in[in_samples - 2];out[(in_samples - 2) * 2 + 1] = static_cast<short>(0.25f * in[in_samples - 2] + 0.75f * in[in_samples - 1]);out[(in_samples - 1) * 2] = in[in_samples - 1];out[(in_samples - 1) * 2 + 1] = in[in_samples - 1];return src_size * 2;
}// 16kHz -> 8kHz 高质量降采样
static int convert_16khz_to_8khz(void *dst_buf, const void *src_buf, int src_size) {short *in = static_cast<short *>(const_cast<void *>(src_buf));short *out = static_cast<short *>(dst_buf);int in_samples = src_size / sizeof(short);// 边界处理out[0] = static_cast<short>(0.8f * in[0] + 0.2f * in[1]);// 主处理循环(带抗混叠滤波的降采样)for (int i = 1; i < in_samples / 2 - 1; ++i) {out[i] = static_cast<short>(0.1f * in[i * 2 - 1] + 0.8f * in[i * 2] + 0.1f * in[i * 2 + 1]);}// 边界处理out[in_samples / 2 - 1] = static_cast<short>(0.2f * in[in_samples - 2] + 0.8f * in[in_samples - 1]);return src_size / 2;
}std::vector<short> ResamplePCM(const std::vector<short> &input,unsigned int inputRate,unsigned int outputRate) {if (inputRate == outputRate) {return input;}std::vector<short> output;if (inputRate == 16000 && outputRate == 8000) {output.resize(input.size() / 2);convert_16khz_to_8khz(output.data(), input.data(), input.size() * sizeof(short));} else if (inputRate == 8000 && outputRate == 16000) {output.resize(input.size() * 2);convert_8khz_to_16khz(output.data(), (void *) input.data(), input.size() * sizeof(short));} else {throw std::runtime_error("仅支持8k<->16k的采样率转换");}return output;
}int main() {try {// 获取项目根目录std::string projectRoot = GetProjectRoot();// 构造完整文件路径std::string inputFile = projectRoot + "bt_pcm_8k.pcm";std::string outputFile = projectRoot + "16k.pcm";const unsigned int inputRate = 8000;const unsigned int outputRate = 16000;// 打印完整路径用于调试std::cout << "输入文件路径: " << inputFile << std::endl;std::cout << "输出文件路径: " << outputFile << std::endl;// 读取PCM文件std::cout << "正在读取文件..." << std::endl;auto pcmData = ReadPCMFile(inputFile);// 重采样std::cout << "正在重采样: " << inputRate << "Hz -> " << outputRate << "Hz\n";auto resampledData = ResamplePCM(pcmData, inputRate, outputRate);// 写入文件std::cout << "正在写入文件..." << std::endl;WritePCMFile(outputFile, resampledData);std::cout << "处理完成! 输出文件已保存为: " << outputFile << std::endl;} catch (const std::exception &e) {std::cerr << "错误: " << e.what() << std::endl;return 1;}return 0;
}
http://www.dtcms.com/a/305743.html

相关文章:

  • 2025年华为HCIA-AI认证是否值得考?还是直接冲击HCIP?
  • c++函数返回值完整总结
  • GaussDB 数据库架构师(十二) 数据库对象修改审计设置
  • (RedmiBook)上禁用触摸板或自带键盘
  • 【LangGraph技术深度解析】构建下一代AI工作流的革命性框架
  • 数据赋能(358)——数据分析——可解释性原则
  • ZKMall商城开源本地部署指南
  • 【Rust多进程】征服CPU的艺术:Rust多进程实战指南
  • 2419. 按位与最大的最长子数组
  • web服务器nginx
  • 新零售“实—虚—合”逻辑下的技术赋能与模式革新:基于开源AI大模型、AI智能名片与S2B2C商城小程序源码的研究
  • 标准七层网络协议和TCP/IP四层协议的区别
  • uni-app webview 的message无法触发的解决方案
  • 在 Elasticsearch 8.19 和 9.1 中引入更强大、更具弹性和可观测性的 ES|QL
  • jenkins连接docker失败【还是没解决】
  • 关于MyBatis 的懒加载(Lazy Loading)机制
  • Hutool 的 WordTree(敏感词检测)
  • 阿里云AI代码助手通义灵码开发指导
  • Javaweb————什么是OPTIONS预检请求
  • 2025年6月数据挖掘顶刊TKDE研究热点有哪些?
  • 磁悬浮技术原理
  • 自动化与配置管理工具 ——Ansible
  • spark入门-helloword
  • React 闭包陷阱及解决方案与 React 16/17/18 版本区别
  • 5种安全方法:如何删除三星手机上的所有内容
  • 三轴云台之减震系统篇
  • OpenEuler 安装 apache + php8 不解析php文件的处理
  • Apache Ignite 2.8 引入的新指标系统(New Metrics System)的完整说明
  • SpringBoot+Three.js打造3D看房系统
  • 深入理解 Doris Compaction:提升查询性能的幕后功臣