CCS环境下C语言VAD实现异常:fread致仅单帧被处理
解决VAD实现中仅处理单帧的问题
问题出在哪?
音频类型完全不匹配
你写的compute_energy和vad函数都是用short处理16位音频样本,但main里偏用char*存数据,fread也按1字节的char读。这会导致两个大问题:- 把读取的字节数当成样本数,实际每个16位样本占2字节,样本数直接少了一半
- 向
vad传char*而不是short*,读取帧的时候内存访问全错,能量计算根本不准
循环读取逻辑没写全
while(num_samples > 0)里面只处理第一次读的数据,根本没再去读文件的后续内容,等于一直死循环处理同一帧(如果没提前终止的话)帧数量计算错了
vad里num_frames = num_samples / FRAME_SIZE,这里的num_samples如果是字节数(不是实际样本数),自然算出来的帧数量不对。比如你读了256字节,当成256个样本,那256/256=1,只会处理1帧。
怎么改?
统一用short存音频数据
- 把
audio_data改成short*,分配内存时按short的大小来 fread时指定sizeof(short),每次读FRAME_SIZE个样本(也就是FRAME_SIZE*2字节)
- 把
补全循环读取逻辑
在while循环末尾再调用一次fread,更新num_samples,直到把文件读完修正样本数的计算逻辑
num_samples是fread返回的实际样本数量,直接用它算帧数量就行
修正后的完整代码
#include <stdio.h> #include <stdlib.h> #include <math.h> #include <errno.h> #include <string.h> #define FRAME_SIZE 256 // 每帧样本数(16位) #define SAMPLE_RATE 16000 // 采样率 #define THRESHOLD 1e7 // 能量阈值 double compute_energy(const short *frame, int frame_size) { double energy = 0.0; int i; for (i = 0; i < frame_size; ++i) { double val = frame[i]; energy += val * val; } return energy; } void vad(const short *audio_data, int num_samples) { int num_frames = num_samples / FRAME_SIZE; printf("NUM FRAMES: %d\n", num_frames); int i; for (i = 0; i < num_frames; ++i) { printf("i VALUE: %d\n", i); // 提取当前帧 const short *frame = &audio_data[i * FRAME_SIZE]; // 计算能量 double energy = compute_energy(frame, FRAME_SIZE); // 语音/静音判断 if (energy > THRESHOLD) { printf("Frame %d: 语音 (能量: %f)\n", i, energy); } else { printf("Frame %d: 静音 (能量: %f)\n", i, energy); } } } int main() { // 16位单声道PCM裸文件路径 const char *file_path = "../example.raw"; // 打开文件 FILE *file = fopen(file_path, "rb"); if (!file) { fprintf(stderr, "打开文件失败 '%s': %s\n", file_path, strerror(errno)); return 1; } // 获取文件大小和总样本数 fseek(file, 0, SEEK_END); long filesize = ftell(file); printf("文件大小: %ld 字节\n", filesize); long total_samples = filesize / sizeof(short); printf("总样本数: %ld\n", total_samples); fseek(file, 0, SEEK_SET); // 分配一帧16位音频的内存 short *audio_data = (short *)malloc(FRAME_SIZE * sizeof(short)); if (!audio_data) { perror("内存分配失败"); fclose(file); return 1; } // 读取第一帧 int num_samples = fread(audio_data, sizeof(short), FRAME_SIZE, file); if (num_samples == 0 && ferror(file)) { perror("文件读取失败"); free(audio_data); fclose(file); return 1; } // 循环处理每一帧 while (num_samples > 0) { printf("进入VAD处理\n"); // 处理当前帧 vad(audio_data, num_samples); // 读取下一帧 num_samples = fread(audio_data, sizeof(short), FRAME_SIZE, file); } // 资源释放 fclose(file); free(audio_data); return 0; }
额外提醒
- 确认你的
example.raw是16位单声道PCM裸数据,如果是8位或立体声,还要对应调整数据类型和读取逻辑 - 能量阈值
THRESHOLD可能需要根据你的实际音频调整,不同场景的能量范围差异很大
内容的提问来源于stack exchange,提问作者posky
相关产品推荐
相关产品推荐

