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.pswp.cn/bicheng/91533.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/91533.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/91533.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【机器学习】机器学习新手入门概述

目录 一、机器学习概念 1.1基本概念 1.2 主要类型 1.2.1 监督学习&#xff08;Supervised Learning&#xff09; &#xff08;1&#xff09;基本介绍 &#xff08;2&#xff09;任务目标 &#xff08;3&#xff09;常见算法 &#xff08;4&#xff09;应用场景 1.2.2 无…

嵌入式硬件篇---ESP32稳压板

制作 ESP32 稳压板的核心目标是&#xff1a;给 ESP32 提供稳定的 3.3V 电源&#xff08;ESP32 的工作电压必须是 3.3V&#xff09;&#xff0c;同时支持多种供电方式&#xff08;比如锂电池、USB、外接电源&#xff09;&#xff0c;并具备保护功能&#xff08;防止过流、接反电…

sql server 删除用户时提示:数据库主体在该数据库中拥有 架构,无法删除

sql server 删除用户时提示&#xff1a;数据库主体在该数据库中拥有 架构&#xff0c;无法删除&#xff0c;怎么办&#xff1f; 1、删除用户ncdb2、 数据库主体在该数据库中拥有 架构&#xff0c;无法删除。3、查看该用户拥有的架构4、找到该用户拥有的这个架构&#xff0c;右键…

分类-鸢尾花分类

目录 基本步骤 决策树&#xff08;分类&#xff09; 导入鸢尾花数据集 赋值给x与y 划分数据集 导入决策树模型 实例化 训练 ​编辑 导入计算准确率的库 计算准确率 随机森林&#xff08;分类&#xff09; 导入鸢尾花的数据集&#xff0c; 赋值x&#xff0c;y 取后一…

单元测试、系统测试、集成测试知识详解

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、单元测试的概念单元测试是对软件基本组成单元进行的测试&#xff0c;如函数或一个类的方法。当然这里的基本单元不仅仅指的是一个函数或者方法&#xff0c;有可…

Python初学OpenCV:图像预处理进阶指南(二)

——实战技巧与创新应用 > 图像预处理是计算机视觉的"基石",掌握它等于获得了让机器"看懂世界"的魔法棒。 在上一篇教程中,我们学习了OpenCV的基础预处理操作。本篇将带你进入图像预处理的进阶世界,通过**实战案例+创新应用**,教你如何组合多种技…

UML类图--基于大话设计模式

类 一般矩形框代表类&#xff0c;类图分为三层&#xff0c;第一层显示类的名称&#xff0c;如果是抽象类&#xff0c;则就用斜体显示&#xff0c;如果是接口&#xff0c;则使用<<interface>>&#xff1b;第二层是类的特性&#xff0c;通常就是字段和属性&#xff1…

数据结构 ArrayList与顺序表

本节目标&#xff1a;了解线性表和顺序表能够实现简单的顺序表及其基本操作认识 ArrayList类并且知道如何去使用本篇文章正式进入数据结构&#xff01;进入之前&#xff0c;先了解一下什么是线性表和顺序表。1.线性表与顺序表线性表线性表&#xff08; linear list &#xff09…

佳维视工业显示器在除尘与过滤设备中的应用

工业显示器凭借高可靠性、防护性能、高显示质量及多功能性&#xff0c;在除尘与过滤设备中扮演着关键角色&#xff0c;其应用贯穿设备监控、数据管理、故障诊断及远程维护全流程&#xff0c;显著提升了设备的运行效率、稳定性和智能化水平。以下是具体应用场景及优势分析&#…

svn与git Merge重要区别讲解

SVN有哪些merge方式 总的来说&#xff0c;SVN 的 merge 主要有以下 五种类型&#xff1a;1. 同步合并 (Sync Merge) / 追赶合并 (Catch-up Merge) 这是在分支开发过程中最常用的一种合并。目的&#xff1a;让你的功能分支保持最新&#xff0c;及时获取主干&#xff08;trunk&am…

Vue 3 入门教程5 - 生命周期钩子

一、生命周期概述Vue 组件从创建到销毁的整个过程称为生命周期&#xff0c;在这个过程中&#xff0c;Vue 会自动触发一系列的函数&#xff0c;这些函数被称为生命周期钩子。通过生命周期钩子&#xff0c;我们可以在组件的不同阶段执行特定的操作&#xff0c;例如初始化数据、发…

负载均衡Haproxy

简介 HAProxy是一款高性能、开源的负载均衡器与反向代理服务器&#xff0c;主要用于 HTTP、TCP等协议的流量分发&#xff0c;广泛应用于高并发、高可用的网络架构中 HAProxy是法国威利塔罗&#xff08;Willy Tarreau&#xff09;使用C语言开发的一个开源软件 企业版&#xff1a…

PostgreSQL锁机制详解:从并发控制到死锁检测

PostgreSQL锁详解 ————向逍xiangxiaohighgo.com 首先要讲锁的话&#xff0c;必须得先了解并发控制。数据库中的对象都是共享的&#xff0c;如果同时间不同的用户对同一个对象进行修改&#xff0c;就会出现数据不一致的情况。所以如果要实现并发访问&#xff0c;就需要对这…

【启发式算法】RRT*算法详细介绍(Python)

&#x1f4e2;本篇文章是博主人工智能&#xff08;AI&#xff09;领域学习时&#xff0c;用于个人学习、研究或者欣赏使用&#xff0c;并基于博主对相关等领域的一些理解而记录的学习摘录和笔记&#xff0c;若有不当和侵权之处&#xff0c;指出后将会立即改正&#xff0c;还望谅…

Docker架构深度解析:从核心概念到企业级实践

Docker架构深度解析&#xff1a;从核心概念到企业级实践一、Docker架构全景图1.1 整体架构示意图二、核心组件深度解析2.1 Docker Daemon工作机制三、镜像与容器原理3.1 镜像分层结构3.2 容器生命周期四、网络架构详解4.1 网络模式对比4.2 Bridge网络实现原理五、存储架构与实践…

PPT自动化 python-pptx - 8: 文本(text)

在使用 python-pptx 库操作 PowerPoint 文档时&#xff0c;理解文本的结构和处理方式至关重要。本文将深入探讨文本在形状中的组织层级、访问方式以及各级别的格式化选项。文本容器与层级结构可容纳文本的形状&#xff1a; 只有自动形状 (Auto shapes) 和表格单元格 (table cel…

使用realsense进行目标检测并标识目标深度

涉及知识点都在代码中注释了&#xff0c;直接看代码 // This example is derived from the ssd_mobilenet_object_detection opencv demo // and adapted to be used with Intel RealSense Cameras // Please see https://github.com/opencv/opencv/blob/master/LICENSE#includ…

OpenWrt Network configuration

OpenWrt Network configuration device 和 interface 关系device device 表示底层的网络设备&#xff0c;如物理网卡、桥接设备&#xff08;bridge&#xff09;、VLAN 设备等。 通过 config device 定义&#xff0c;描述设备类型、端口成员、VLAN 等属性。 例如&#xff1a;br…

VuePress 使用详解

一、核心概念 VuePress 是 Vue.js 团队开发的静态网站生成器&#xff0c;专为技术文档优化&#xff0c;具备以下特性&#xff1a; Markdown 优先&#xff1a;原生支持 Markdown 语法扩展Vue 驱动&#xff1a;可在 Markdown 中使用 Vue 组件默认主题优化&#xff1a;内置响应式…

AI大模型前沿:Muyan-TTS开源零样本语音合成技术解析

AI大模型前沿&#xff1a;Muyan-TTS开源零样本语音合成技术解析引言&#xff1a;语音合成技术的演进与Muyan-TTS的突破性意义语音合成&#xff08;Text-to-Speech, TTS&#xff09;技术作为人机交互的核心接口之一&#xff0c;自20世纪30年代贝尔实验室首次尝试电子语音合成以来…