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