You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CCS环境下C语言VAD实现异常:fread致仅单帧被处理

解决VAD实现中仅处理单帧的问题

问题出在哪?

  1. 音频类型完全不匹配
    你写的compute_energy和vad函数都是用short处理16位音频样本,但main里偏用char*存数据,fread也按1字节的char读。这会导致两个大问题:

    • 把读取的字节数当成样本数,实际每个16位样本占2字节,样本数直接少了一半
    • 向vad传char*而不是short*,读取帧的时候内存访问全错,能量计算根本不准
  2. 循环读取逻辑没写全
    while(num_samples > 0)里面只处理第一次读的数据,根本没再去读文件的后续内容,等于一直死循环处理同一帧(如果没提前终止的话)

  3. 帧数量计算错了
    vad里num_frames = num_samples / FRAME_SIZE,这里的num_samples如果是字节数(不是实际样本数),自然算出来的帧数量不对。比如你读了256字节,当成256个样本,那256/256=1,只会处理1帧。

怎么改?

  1. 统一用short存音频数据

    • 把audio_data改成short*,分配内存时按short的大小来
    • fread时指定sizeof(short),每次读FRAME_SIZE个样本(也就是FRAME_SIZE*2字节)
  2. 补全循环读取逻辑
    在while循环末尾再调用一次fread,更新num_samples,直到把文件读完

  3. 修正样本数的计算逻辑
    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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 20:24:55