当前位置: 首页 > 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.lryc.cn/news/605106.html

相关文章:

  • 不同环境安装配置redis
  • 网络端口号全景解析:从基础服务到特殊应用的完整指南
  • 代码随想录算法训练营第三十六天
  • 【git】GitHub 的专用代理地址
  • day21-Excel文件解析
  • uvm-tlm-port-export-imp
  • 在VS2022中调试ASP.NET项目时修改DLL或ASPX动态页面的原理及实现方法
  • STM32CubeIDE新建项目过程记录备忘(二) GPIO输出demo:LED闪烁
  • 2025 IT专业人才培养趋势与职业发展指南:技术+数据复合型能力的构建路径
  • 【Kubernetes 指南】基础入门——Kubernetes 201(一)
  • OpenEuler 安装 apache + php8 不解析php文件的处理
  • 微信小程序中实现页面跳转的方法
  • Python奇幻之旅:从零开始的编程冒险
  • cpp-httplib 线程安全
  • mybatis中的极易出现错误用法
  • Chroma安装教程
  • uni-app webview的message监听不生效(uni.postmessage is not a function)
  • 明智运用C++异常规范(Exception Specifications)
  • 监测预警系统:让园区更高效、更安全、更智能
  • [Python] -进阶理解10- 用 Python 实现简易爬虫框架
  • Android Animation Transitions:打造流畅的用户体验
  • 性能优化(一):时间分片(Time Slicing):让你的应用在高负载下“永不卡顿”的秘密
  • vue模块化导入
  • DooTask教育行业功能:开启高效学习协作新篇章
  • 学习嵌入式第十五天
  • 【PostgreSQL内核学习:WindowAgg 帧优化与节点去重】
  • 李宏毅2025《机器学习》-第九讲:大型语言模型评测的困境与“古德哈特定律”**
  • Linux 中,命令查看系统版本和内核信息
  • LNN+XGBoost:优化多层供应链订购:缓解牛鞭效应
  • 力扣209:长度最小的子数组