音频 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);