音频 float 32 48KHz 和 signed int 16 16KHz 的相互转换

float 32 48KHz 转 signed int 16 16KHz

采样率,是一秒内含有多少样本数量,48K则代表一秒内有48000个采样点;16K,则代表一秒内有16000个采样点。

48K转16K是从高到低的转换,只需要丢弃部分样本即可完成转换,16/48=3,故选择每三帧取一帧。

 

float32格式的音频,波形在±1之内,区间为(-1.0, +1.0);int16,波形区间(-32766, 32767),因而转换过程只需要将每个采样点乘以32767.0后取整即可。

 

float** adata = (float**)audio->data;    // 原始的48K float数据

short* sbuf = (short*)malloc(sizeof(short) * audio->frames);    // 转换后的结果

for (int i = 0; i < audio->frames; ++i) {
    //每三帧留一帧,完成采样率转换
    if (i % 3 != 0)
        continue;

    // 对于超出int16范围的结果规定取int16的极值,防止溢出(在波形种会产生竖线杂音)
    if (adata[0][i] < -0.999999f)
        sbuf[i / 3] = INT16_MIN;
    else if (adata[0][i] > 0.999999f)
        sbuf[i / 3] = INT16_MAX;
    else
        sbuf[i / 3] = adata[0][i] * (32767.0f);
}

// ......

free(sbuf);

signed int 16 16KHz 转 float 32 48KHz

反向转换相对麻烦

由于是由少到多,需要在两帧之间进行插值,这里采用平均插值,即将两帧之间的差值均分后按大小插入相对维持了波形的趋势。

s16转回float相对简单,除回去就可以了。

大家不要像我一样new 和 malloc 混合使用,这里只是思路

 

int16_t* ba = (int16_t*)i16pcm;        // 需要转换的原始数据

int n = 48/16;    // 采样率的放大倍率

// 样本总数量
int baFrameCount = bar.size() / sizeof(int16_t);
int if48FrameCount  = bar.size() * n / sizeof(int16_t);

int16_t* i48pcm = new int16_t[if48FrameCount];

// 插值处理,16K转48K
for (int i = 0; i < baFrameCount; ++i) {
    for (int j = 0; j < n; ++j) {
        i48pcm[i*n+j] = ((i >(baFrameCount) - 2) ?
            ba[i] + (0 - ba[i]) / n * j:
            ba[i] + ((ba[i + 1] - ba[i]) / n * j));
    }
}

// int16 转 float
float* f48pcm = (float*)malloc(if48FrameCount*sizeof(float));
for (int i = 0; i < if48FrameCount; ++i) {
    f48pcm[i] = (float)i48pcm[i] / 32767.0f;
}
delete[] i48pcm;

// ......

free(f48pcm);

 

posted @ 2022-03-28 11:18  ╰⋛⊱๑飘遥๑⊰⋚╯  阅读(810)  评论(0编辑  收藏  举报