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;
}