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.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年代貝爾實驗室首次嘗試電子語音合成以來…