基于C语言实现PCM音频流或音频文件重采样(48K到16K)

基于C语言实现PCM音频流或音频文件重采样(48K到16K)

由于云厂商SDK需要的音频采样率是16K的,而SFU回调上来的流是48K的,所以我们还需要对PCM音频数据进行重采样处理。

​ 转换的原理比较简单,从48KHz降到16KHz,降了3倍,也就是说在同一时间的单位区间内,48KHz采样了3个点,而16KHz只采样了1个点,即从48KHz的 PCM流中每读取3个数据,就要根据这3个数据去推算得到1个数据,而这个数据对应的就是16KHz PCM流中的一个数据。

重采样

我们有很多种方法可以由3个数据得到1个数据,如取平均值,取采样点等方法:

(1). 取平均值:

取3个点,相加后求平均值。这样的效果并不好,转换后声音会有杂音。这是因为转换成16kHz的采样率时,根据奈奎斯特采样定律,当采样频率fs.max大于信号中最高频率fmax的2倍时(fs.max>2fmax),,那么根据这些抽样值就能完全恢复原信号,所以转换成16kHz的采样率时,不能有8K以上的频率。而对3个点求平均值,是会有概率存在着8khz以上的频段,故效果并不好。

(2). 取特征点:

取3个采样点中固定位置的某个点,如固定取3个点中的第一个点,然后合并成新的数据流。这样的效果,实测比较清晰,虽然有概率会丢失部分声音细节,但是整体还是能够满足语音识别。

综上所述,我们采取第一个特征点的方法。

具体实现如下

C语言实现

处理pcm流:

/** PCM frame. */
typedef struct {
    uint8_t        *buf;
    int             len;
    int             sample_rate;
    int             sample_depth;
} pcm_frame_t;

void pcm_resample_16k(const pcm_frame_t *frame_in, pcm_frame_t *frame_out)
{
    int i;
    int magnification = frame_in->sample_rate / 16000;

    frame_out->buf = frame_in->buf;
    frame_out->len = frame_in->len / magnification;
    frame_out->sample_rate = 16000;
    frame_out->sample_depth = frame_in->sample_depth;


    for (i = 0; i < frame_out->len; i++) {
        frame_out->buf[i] = frame_in->buf[i*magnification]; /* 取第一个特征值 */
    }


    /* 如果按照16bit来 */
//     for (i = 0; i < len / 3; i++) {
//         if (0 == (i % 2)) {
//             buf[i] = buf[i*3+2];
//         } else {
//             buf[i] = buf[i*3];
//         }
//     }
}

处理pcm文件:

void pcm_resample(void)
{
    short read_buf = 0;
    int size = 0;
    int cnt = 0;

    FILE *fp = fopen("in.pcm", "rb+");
    FILE *fp_out = fopen("out.pcm", "wb+");

    while (!feof(fp)) {
        size = fread(&read_buf, 2, 1, fp); // 16bit,所以需要一次读两个字节
        if (size > 0) {
            cnt++;
            if (cnt == 3) { //每采集到3个点
                cnt = 0; // 重置计数
                fwrite(&read_buf, 2, 1, fp_out); //写入数据
            }
        }
    }

    fclose(fp);
    fclose(fp_out);
}
  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值