MPEG-1 Audio Layer II編碼原理及編碼器調試
模擬音頻信號數字化後通常具有極高的碼率,例如對於取樣頻率爲44.1 kHz的雙聲道CD數字音頻而言,採用16 bit量化,無壓縮碼率可達1.41 Mbps,非常不利於存儲和傳輸。因此,爲了節省存儲空間、提高傳輸效率,必須要對數字音頻信號進行壓縮編碼。
一. 數字音頻信號壓縮的可能性
無壓縮的數字音頻信號中主要存在兩方面的冗餘信息:
一是聲音信號中本身存在的冗餘:信號幅度分佈是非均勻的(小幅度的樣值比大幅度樣值出現的概率高),且樣本之間存在相關性(時域冗餘);
二是根據人耳的聽覺特性,可不對與聽覺無關的部分編碼(具體內容見後)。
二. 人類聽覺系統的感知特性
1. 等響度曲線
圖中每條曲線代表的(人耳感受的)響度相同,最下方一條曲線代表最小可聽閾,其下方區域的聲音人耳無法察覺,因此可以不編碼。
2. 頻域掩蔽效應
一個高強度純音會使得該頻率附近的最小可聽閾曲線提升,掩蔽掉在其下的(原本能聽到的)聲音。這個純音稱爲掩蔽聲,掩蔽聲存在時,音調音剛剛能被聽到時的閾值稱爲掩蔽閾值。
因此在編碼時,可以去除掩蔽閾值以下的信號分量,並忽略可能會被掩蔽的量化噪聲。
掩蔽曲線具有以下特點:
- 不對稱,高頻一端的斜率絕對值更小;
- 低頻音易對高頻音產生掩蔽;
- 掩蔽聲強度越高、頻率越高,掩蔽的頻率範圍越寬。
3. 臨界頻帶(Critical Band)
臨界頻帶具有兩種等價的定義:
-
定義一:當某個純音被以它爲中心頻率、且具有一定帶寬的連續噪聲所掩蔽時,如果該純音剛好被聽到時的功率等於這一頻帶內的噪聲功率,這個帶寬爲臨界頻帶寬度;
-
定義二:如果增大掩蔽信號覆蓋的頻率範圍,超過到某個值後掩蔽效應不再隨着帶寬的增大而增強,這個臨界的帶寬就稱爲臨界頻帶。
其單位爲Bark,代表一個臨界頻帶的寬度。
通常認爲,在20 Hz—16 kHz的範圍內有25個臨界頻帶(500 Hz以下每個臨界頻帶的帶寬大約是100 Hz,500 Hz以上的臨界頻帶帶寬逐漸增加)。
4. 人類聽覺系統
人類聽覺系統可以大致等效爲在0 Hz—20 kHz範圍內的25個重疊的帶通濾波器組。
-
人耳在噪聲中聽某一純音信號時,只啓用中心頻率與信號頻率相同的那個聽覺濾波器,且只有純音信號和在通帶範圍內的部分信號可通過該濾波器。只有通過該濾波器的噪聲纔對掩蔽起作用;
-
聆聽複音時啓動多個聽覺濾波器。聽覺能夠計算各濾波器輸出端的信噪比。當信噪比達到或者超過聽閾因子時,即可聽到該頻率成分。
人耳聽覺系統
5. 時域掩蔽效應
由於在時間上相鄰的聲音之間存在超前掩蔽(5—20 ms)和滯後掩蔽(50—200 ms),因此在編碼時,可將時間上相繼的一些樣值歸併成塊,並計算每塊內最大樣值的比例因子。
三. MPEG-1音頻壓縮編碼
MPEG-1中採用了感知音頻編碼,Layer II的編碼器框圖如下。
下面以Layer II爲基準,簡要說明編碼器的組成和編碼過程。
1. 多相濾波器
數字音頻信號通過一個多相濾波器組,變換成32個等寬頻帶子帶,使得信號具有較高的時間分辨率,確保在短暫衝擊信號的情況下,編碼的聲音信號具有足夠高的質量。
但需要說明的是,高時域分辨率和高頻域分辨率是不可兼得的,我們需要做出權衡。
濾波器組的輸出是臨界頻帶經過量化的係數樣值。若一個子帶覆蓋多個臨界頻帶,則選擇具有最小NMR的臨界頻帶來計算分配給子帶的比特數。
2. 心理聲學模型
心理聲學模型決定了各個子帶中允許的最大量化噪聲,小於它的量化噪聲都會被掩蔽。若子帶內的信號功率小於掩蔽閾值,則不進行編碼;否則,確定要編碼的係數所需的比特數,使量化引起的噪聲低於掩蔽效應;
-
使用FFT將音頻樣值變換到頻域。這裏Layer II採用1024點FFT(Layer I中採用512點),提高了頻率分辨率,可以得到更準確的頻譜特性;
-
將得到的頻率組成臨界頻帶;
-
由於樂音和非樂音(噪聲)信號的掩蔽能力不同,因此在臨界頻帶的譜值中,將兩種信號分離:可將局部峯值視爲樂音,然後將本臨界頻帶內的剩餘頻譜組成一個代表噪聲頻率(無調成份);
樂音和非樂音(噪聲)的掩蔽能力不同 -
計算每個子帶的全局掩蔽閾值(以頻率爲自變量);
全局掩蔽閾值的計算公式 -
計算每個子帶的SMR(每8 ms計算一個);
3. 量化編碼
(1) 比特分配
比特分配:對每個子帶計算**掩噪比MNR (dB) = 信噪比SNR - 信掩比SMR,然後找出其中具有最低MNR的子帶,並給該子帶多分配一些比特,然後重新計算MNR,繼續分配,重複該步驟,直至沒有比特可以分配。這樣可以使得在滿足比特率和掩蔽要求的前提下,使MNR最小**;
(2) 計算比例因子
- 對各個子帶每36個樣點(Layer I爲12個樣點)進行一次比例因子的計算,先確定12個連續樣值中的最大值,查Layer II、Layer I比例因子表中比這它大的最小值作爲量化比例因子;
- 每12個樣值計算出一個比例因子,Layer II中將每個子帶分爲3組,每組各有12個取樣值,因此36個樣值具有3個比例因子;
- 比例因子可以使得比較準確地計算出子帶的聲壓級;
- 一般比例因子從低頻子帶到高頻子帶連續下降;
(3) 子帶樣值量化
將子帶樣值除以比例因子(結果爲),根據所分配的比特數查表得、,量化結果爲。
(4) 顆粒形成
對量化級別在3、5、9級時,採用“顆粒” 優化。例如:
- 採用顆粒量化:3個樣本 @ 3個量化水平 = 27種可能的值 → 5 bit
- 不採用顆粒量化:1個樣本 @ 3個量化水平 = 2bit → 3個樣本6 bit
- 經過大量實驗,使用顆粒量化可將壓縮比從4:1增加到6:1乃至8:1
4. 幀比特流形成
- 其中每個子帶中前後相鄰的連續36個樣值(3組12個樣值)共用在這個子帶比特分配值,36個樣值中的同一組樣值共用該組的比例因子;
- 同一時刻的32個子帶樣值放在一起;
- Layer II每幀包含1152個PCM樣值(爲Layer I的三倍);
- 若取樣頻率爲48 kHz,一幀相當於1152 / 48k = 24 ms的聲音樣值,因此Layer II的精確度爲24 ms(爲Layer I的三倍,因而更精確)。
四. MPEG-1 Audio Layer II編碼器調試
1. 編碼流程
下面是編碼器main()
函數部分的代碼,可以結合上面的編碼步驟,並結合註釋進行理解。
int main(int argc, char** argv) {
typedef double SBS[2][3][SCALE_BLOCK][SBLIMIT];
SBS* sb_sample;
typedef double JSBS[3][SCALE_BLOCK][SBLIMIT];
JSBS* j_sample;
typedef double IN[2][HAN_SIZE];
IN* win_que;
typedef unsigned int SUB[2][3][SCALE_BLOCK][SBLIMIT];
SUB* subband;
frame_info frame; // 包含頭信息、比特分配表、聲道數、子帶數等內容
frame_header header; // 包含採樣頻率等信息
char original_file_name[MAX_NAME_SIZE]; // 輸入文件名
char encoded_file_name[MAX_NAME_SIZE]; // 輸出文件名
short** win_buf;
static short buffer[2][1152];
static unsigned int bit_alloc[2][SBLIMIT]; // 存放雙聲道各個子帶的比特分配表
static unsigned int scfsi[2][SBLIMIT];
static unsigned int scalar[2][3][SBLIMIT]; // 存放雙聲道3組12個樣值的各個子帶的比例因子
static unsigned int j_scale[3][SBLIMIT];
static double smr[2][SBLIMIT], lgmin[2][SBLIMIT], max_sc[2][SBLIMIT];
// FLOAT snr32[32];
short sam[2][1344]; /* was [1056]; */
int model;
int nch; // 聲道數
int error_protection;
static unsigned int crc;
int sb, ch;
int adb; // 比特預算 (i.e., number of bits available)
unsigned long frameBits, sentBits = 0;
unsigned long num_samples;
int lg_frame;
int i;
/* Used to keep the SNR values for the fast/quick psy models */
static FLOAT smrdef[2][32];
static int psycount = 0;
extern int minimum;
time_t start_time, end_time;
int total_time;
sb_sample = (SBS*)mem_alloc(sizeof(SBS), "sb_sample");
j_sample = (JSBS*)mem_alloc(sizeof(JSBS), "j_sample");
win_que = (IN*)mem_alloc(sizeof(IN), "Win_que");
subband = (SUB*)mem_alloc(sizeof(SUB), "subband");
win_buf = (short**)mem_alloc(sizeof(short*) * 2, "win_buf");
/* clear buffers */
memset((char*)buffer, 0, sizeof(buffer));
memset((char*)bit_alloc, 0, sizeof(bit_alloc));
memset((char*)scalar, 0, sizeof(scalar));
memset((char*)j_scale, 0, sizeof(j_scale));
memset((char*)scfsi, 0, sizeof(scfsi));
memset((char*)smr, 0, sizeof(smr));
memset((char*)lgmin, 0, sizeof(lgmin));
memset((char*)max_sc, 0, sizeof(max_sc));
//memset ((char *) snr32, 0, sizeof (snr32));
memset((char*)sam, 0, sizeof(sam));
global_init();
header.extension = 0;
frame.header = &header;
frame.tab_num = -1; /* no table loaded */
frame.alloc = NULL;
header.version = MPEG_AUDIO_ID; /* Default: MPEG-1 */
total_time = 0;
time(&start_time);
programName = argv[0]; // exe文件名稱
if (argc == 1) /* no command-line args */
short_usage();
else
parse_args(argc, argv, &frame, &model, &num_samples, original_file_name, encoded_file_name); // 解析命令行參數
print_config(&frame, &model, original_file_name, encoded_file_name); // print文件參數到窗口
/* this will load the alloc tables and do some other stuff */
hdr_to_frps(&frame);
nch = frame.nch;
error_protection = header.error_protection;
/* 從數據流獲取音頻 */
while (get_audio(musicin, buffer, num_samples, nch, &header) > 0) {
/* 從輸入的文件讀取數據到buffer */
if (glopts.verbosity > 1)
if (++frameNum % 10 == 0) /* 出錯 */
fprintf(stderr, "[%4u]\r", frameNum);
fflush(stderr);
win_buf[0] = &buffer[0][0];
win_buf[1] = &buffer[1][0];
adb = available_bits(&header, &glopts); // 計算比特預算
lg_frame = adb / 8;
if (header.dab_extension) {
/* in 24 kHz we always have 4 bytes */
if (header.sampling_frequency == 1)
header.dab_extension = 4;
/* You must have one frame in memory if you are in DAB mode */
/* in conformity of the norme ETS 300 401 http://www.etsi.org */
/* see bitstream.c */
if (frameNum == 1)
minimum = lg_frame + MINIMUM;
adb -= header.dab_extension * 8 + header.dab_length * 8 + 16;
}
{
int gr, bl, ch;
/* New polyphase filter
Combines windowing and filtering. Ricardo Feb'03 */
for (gr = 0; gr < 3; gr++) /* 36個樣值分爲3組 */
for (bl = 0; bl < 12; bl++) /* 每組做12次子帶分解 */
for (ch = 0; ch < nch; ch++)
WindowFilterSubband(&buffer[ch][gr * 12 * 32 + 32 * bl], ch, &(*sb_sample)[ch][gr][bl][0]); /* 多相濾波器組 */
}
#ifdef REFERENCECODE
{
/* Old code. left here for reference */
int gr, bl, ch;
for (gr = 0; gr < 3; gr++)
for (bl = 0; bl < SCALE_BLOCK; bl++)
for (ch = 0; ch < nch; ch++) {
window_subband(&win_buf[ch], &(*win_que)[ch][0], ch);
filter_subband(&(*win_que)[ch][0], &(*sb_sample)[ch][gr][bl][0]);
}
}
#endif
#ifdef NEWENCODE
scalefactor_calc_new(*sb_sample, scalar, nch, frame.sblimit);
find_sf_max(scalar, &frame, max_sc);
if (frame.actual_mode == MPG_MD_JOINT_STEREO) {
/* this way we calculate more mono than we need */
/* but it is cheap */
combine_LR_new(*sb_sample, *j_sample, frame.sblimit);
scalefactor_calc_new(j_sample, &j_scale, 1, frame.sblimit);
}
#else
scale_factor_calc(*sb_sample, scalar, nch, frame.sblimit); // 計算比例因子
pick_scale(scalar, &frame, max_sc); // 選擇比例因子
if (frame.actual_mode == MPG_MD_JOINT_STEREO) { /* 先忽略 */
/* this way we calculate more mono than we need */
/* but it is cheap */
combine_LR(*sb_sample, *j_sample, frame.sblimit);
scale_factor_calc(j_sample, &j_scale, 1, frame.sblimit);
}
#endif
/* 選擇心理聲學模型,計算SMR */
if ((glopts.quickmode == TRUE) && (++psycount % glopts.quickcount != 0)) {
/* We're using quick mode, so we're only calculating the model every
'quickcount' frames. Otherwise, just copy the old ones across */
for (ch = 0; ch < nch; ch++) {
for (sb = 0; sb < SBLIMIT; sb++)
smr[ch][sb] = smrdef[ch][sb];
}
} else {
/* calculate the psymodel */
switch (model) {
case -1:
psycho_n1(smr, nch);
break;
case 0: /* Psy Model A */
psycho_0(smr, nch, scalar, (FLOAT)s_freq[header.version][header.sampling_frequency] * 1000); // smr爲輸出
break;
case 1:
psycho_1(buffer, max_sc, smr, &frame);
break;
case 2:
for (ch = 0; ch < nch; ch++) {
psycho_2(&buffer[ch][0], &sam[ch][0], ch, &smr[ch][0], //snr32,
(FLOAT)s_freq[header.version][header.sampling_frequency] *
1000, &glopts);
}
break;
case 3:
/* Modified psy model 1 */
psycho_3(buffer, max_sc, smr, &frame, &glopts);
break;
case 4:
/* Modified Psycho Model 2 */
for (ch = 0; ch < nch; ch++) {
psycho_4(&buffer[ch][0], &sam[ch][0], ch, &smr[ch][0], // snr32,
(FLOAT)s_freq[header.version][header.sampling_frequency] *
1000, &glopts);
}
break;
case 5:
/* Model 5 comparse model 1 and 3 */
psycho_1(buffer, max_sc, smr, &frame);
fprintf(stdout, "1 ");
smr_dump(smr, nch);
psycho_3(buffer, max_sc, smr, &frame, &glopts);
fprintf(stdout, "3 ");
smr_dump(smr, nch);
break;
case 6:
/* Model 6 compares model 2 and 4 */
for (ch = 0; ch < nch; ch++)
psycho_2(&buffer[ch][0], &sam[ch][0], ch, &smr[ch][0], //snr32,
(FLOAT)s_freq[header.version][header.sampling_frequency] *
1000, &glopts);
fprintf(stdout, "2 ");
smr_dump(smr, nch);
for (ch = 0; ch < nch; ch++)
psycho_4(&buffer[ch][0], &sam[ch][0], ch, &smr[ch][0], // snr32,
(FLOAT)s_freq[header.version][header.sampling_frequency] *
1000, &glopts);
fprintf(stdout, "4 ");
smr_dump(smr, nch);
break;
case 7:
fprintf(stdout, "Frame: %i\n", frameNum);
/* Dump the SMRs for all models */
psycho_1(buffer, max_sc, smr, &frame);
fprintf(stdout, "1");
smr_dump(smr, nch);
psycho_3(buffer, max_sc, smr, &frame, &glopts);
fprintf(stdout, "3");
smr_dump(smr, nch);
for (ch = 0; ch < nch; ch++)
psycho_2(&buffer[ch][0], &sam[ch][0], ch, &smr[ch][0], //snr32,
(FLOAT)s_freq[header.version][header.sampling_frequency] *
1000, &glopts);
fprintf(stdout, "2");
smr_dump(smr, nch);
for (ch = 0; ch < nch; ch++)
psycho_4(&buffer[ch][0], &sam[ch][0], ch, &smr[ch][0], // snr32,
(FLOAT)s_freq[header.version][header.sampling_frequency] *
1000, &glopts);
fprintf(stdout, "4");
smr_dump(smr, nch);
break;
case 8:
/* Compare 0 and 4 */
psycho_n1(smr, nch);
fprintf(stdout, "0");
smr_dump(smr, nch);
for (ch = 0; ch < nch; ch++)
psycho_4(&buffer[ch][0], &sam[ch][0], ch, &smr[ch][0], // snr32,
(FLOAT)s_freq[header.version][header.sampling_frequency] *
1000, &glopts);
fprintf(stdout, "4");
smr_dump(smr, nch);
break;
default:
fprintf(stderr, "Invalid psy model specification: %i\n", model);
exit(0);
}
if (glopts.quickmode == TRUE)
/* copy the smr values and reuse them later */
for (ch = 0; ch < nch; ch++) {
for (sb = 0; sb < SBLIMIT; sb++)
smrdef[ch][sb] = smr[ch][sb];
}
if (glopts.verbosity > 4)
smr_dump(smr, nch);
}
#ifdef NEWENCODE
sf_transmission_pattern(scalar, scfsi, &frame);
main_bit_allocation_new(smr, scfsi, bit_alloc, &adb, &frame, &glopts);
//main_bit_allocation (smr, scfsi, bit_alloc, &adb, &frame, &glopts);
if (error_protection)
CRC_calc(&frame, bit_alloc, scfsi, &crc);
write_header(&frame, &bs);
//encode_info (&frame, &bs);
if (error_protection)
putbits(&bs, crc, 16);
write_bit_alloc(bit_alloc, &frame, &bs);
//encode_bit_alloc (bit_alloc, &frame, &bs);
write_scalefactors(bit_alloc, scfsi, scalar, &frame, &bs);
//encode_scale (bit_alloc, scfsi, scalar, &frame, &bs);
subband_quantization_new(scalar, *sb_sample, j_scale, *j_sample, bit_alloc,
*subband, &frame);
//subband_quantization (scalar, *sb_sample, j_scale, *j_sample, bit_alloc,
// *subband, &frame);
write_samples_new(*subband, bit_alloc, &frame, &bs);
//sample_encoding (*subband, bit_alloc, &frame, &bs);
#else
transmission_pattern(scalar, scfsi, &frame);
main_bit_allocation(smr, scfsi, bit_alloc, &adb, &frame, &glopts); // 比特分配
if (error_protection)
CRC_calc(&frame, bit_alloc, scfsi, &crc);
encode_info(&frame, &bs); // 編碼
if (error_protection)
encode_CRC(crc, &bs);
encode_bit_alloc(bit_alloc, &frame, &bs);
encode_scale(bit_alloc, scfsi, scalar, &frame, &bs);
subband_quantization(scalar, *sb_sample, j_scale, *j_sample, bit_alloc, *subband, &frame); // 量化
sample_encoding(*subband, bit_alloc, &frame, &bs);
#endif
/* If not all the bits were used, write out a stack of zeros */
for (i = 0; i < adb; i++)
put1bit(&bs, 0);
if (header.dab_extension) {
/* Reserve some bytes for X-PAD in DAB mode */
putbits(&bs, 0, header.dab_length * 8);
for (i = header.dab_extension - 1; i >= 0; i--) {
CRC_calcDAB(&frame, bit_alloc, scfsi, scalar, &crc, i);
/* this crc is for the previous frame in DAB mode */
if (bs.buf_byte_idx + lg_frame < bs.buf_size)
bs.buf[bs.buf_byte_idx + lg_frame] = crc;
/* reserved 2 bytes for F-PAD in DAB mode */
putbits(&bs, crc, 8);
}
putbits(&bs, 0, 16);
}
frameBits = sstell(&bs) - sentBits;
if (frameBits % 8) { /* a program failure */
fprintf(stderr, "Sent %ld bits = %ld slots plus %ld\n", frameBits,
frameBits / 8, frameBits % 8);
fprintf(stderr, "If you are reading this, the program is broken\n");
fprintf(stderr, "email [mfc at NOTplanckenerg.com] without the NOT\n");
fprintf(stderr, "with the command line arguments and other info\n");
exit(0);
}
sentBits += frameBits;
}
close_bit_stream_w(&bs);
if ((glopts.verbosity > 1) && (glopts.vbr == TRUE)) {
int i;
#ifdef NEWENCODE
extern int vbrstats_new[15];
#else
extern int vbrstats[15];
#endif
fprintf(stdout, "VBR stats:\n");
for (i = 1; i < 15; i++)
fprintf(stdout, "%4i ", bitrate[header.version][i]);
fprintf(stdout, "\n");
for (i = 1; i < 15; i++)
#ifdef NEWENCODE
fprintf(stdout, "%4i ", vbrstats_new[i]);
#else
fprintf(stdout, "%4i ", vbrstats[i]);
#endif
fprintf(stdout, "\n");
}
fprintf(stderr,
"Avg slots/frame = %.3f; b/smp = %.2f; bitrate = %.3f kbps\n",
(FLOAT)sentBits / (frameNum * 8),
(FLOAT)sentBits / (frameNum * 1152),
(FLOAT)sentBits / (frameNum * 1152) *
s_freq[header.version][header.sampling_frequency]);
if (fclose(musicin) != 0) {
fprintf(stderr, "Could not close \"%s\".\n", original_file_name);
exit(2);
}
fprintf(stderr, "\nDone\n");
time(&end_time);
total_time = end_time - start_time;
printf("total time is %d\n", total_time);
exit(0);
}
2. 命令行設置
最基本的命令行參數如下:
輸入文件名 輸出文件名
此時使用默認的輸出比特率(192 kbps)。
此外,我們還可以參考usage()
函數來自定額外的輸出參數,如:
-b 48 -a 輸入文件名 輸出文件名
可將輸出比特率設爲48 kbps,並輸出單聲道音頻。
3. 輸出一幀的比例因子和比特分配表
定義文件指針:FILE* infoFp;
爲了保證程序的簡明與運行流暢,將需要觀測的內容輸出到TRACE文件,因此在文件開頭位置定義宏:#define FRAME_TRACE 1
,這樣設爲1時就打開數據幀的TRACE文件。
先在print_config()
函數中輸出一些輸入、輸出文件的主要參數(參考函數中的寫法即可):
#if FRAME_TRACE
fprintf(infoFp, "========== 基本信息 ==========\n");
fprintf(infoFp, "輸入文件:%s\n", inPath);
fprintf(infoFp, "輸出文件:%s\n", outPath);
fprintf(infoFp, "採樣頻率:%.1f kHz\n", s_freq[header->version][header->sampling_frequency]);
fprintf(infoFp, "輸出文件碼率:%d kbps\n", bitrate[header->version][header->bitrate_index]);
#endif // FRAME_TRACE
然後輸出比例因子和比特分配表,在main()
中添加:
/* 打開文件等步驟略 */
...
#else
scale_factor_calc(*sb_sample, scalar, nch, frame.sblimit); // 計算比例因子
pick_scale(scalar, &frame, max_sc); // pick比例因子
/********** Added by S.Z.Zheng **********/
#if FRAME_TRACE
if (frameNum == 2) {
fprintf(infoFp, "聲道數:%d\n", nch);
fprintf(infoFp, "目前觀測第 %d 幀\n", frameNum);
fprintf(infoFp, "本幀比特預算:%d bits\n", adb);
fprintf(infoFp, "\n");
/* 比例因子 */
fprintf(infoFp, "========== 比例因子 ==========\n");
for (ch = 0; ch < nch; ch++) // 每個聲道單獨輸出
{
fprintf(infoFp, "------ 聲道%2d ------\n", ch + 1);
for (sb = 0; sb < frame.sblimit; sb++) // 每個子帶
{
fprintf(infoFp, "子帶[%2d]:\t", sb + 1);
for (int gr = 0; gr < 3; gr++) {
fprintf(infoFp, "%2d\t", scalar[ch][gr][sb]);
}
fprintf(infoFp, "\n");
}
}
fprintf(infoFp, "\n");
/* 比特分配表 */
fprintf(infoFp, "========== 比特分配表 ==========\n"); //輸出比特分配結果
for (ch = 0; ch < nch; ch++) {
fprintf(infoFp, "------ 聲道%2d ------\n", ch + 1); //按聲道分配
for (sb = 0; sb < frame.sblimit; sb++) {
fprintf(infoFp, "子帶[%2d]:\t%2d\n", sb + 1, bit_alloc[ch][sb]);
}
fprintf(infoFp, "\n");
}
}
#endif // FRAME_TRACE
/********** Addition ended **********/
...
五. 測試結果
1. 樂音
========== 基本信息 ==========
輸入文件:music.wav
輸出文件:music_192k.mp2
採樣頻率:44.1 kHz
輸出文件碼率:192 kbps
聲道數:2
目前觀測第 2 幀
本幀比特預算:5016 bits
========== 比例因子 ==========
------ 聲道 1 ------
子帶[ 1]: 33 35 35
子帶[ 2]: 44 41 41
子帶[ 3]: 47 46 46
子帶[ 4]: 47 46 45
子帶[ 5]: 46 44 47
子帶[ 6]: 50 47 48
子帶[ 7]: 46 49 49
子帶[ 8]: 47 48 48
子帶[ 9]: 49 48 48
子帶[10]: 49 46 47
子帶[11]: 48 47 48
子帶[12]: 46 48 48
子帶[13]: 49 48 48
子帶[14]: 47 51 50
子帶[15]: 49 49 48
子帶[16]: 50 46 49
子帶[17]: 51 50 48
子帶[18]: 51 50 51
子帶[19]: 52 49 51
子帶[20]: 51 49 49
子帶[21]: 49 51 50
子帶[22]: 51 49 52
子帶[23]: 48 49 50
子帶[24]: 54 52 55
子帶[25]: 54 56 54
子帶[26]: 55 54 54
子帶[27]: 53 54 53
子帶[28]: 54 54 54
子帶[29]: 54 56 53
子帶[30]: 55 56 55
------ 聲道 2 ------
子帶[ 1]: 34 34 36
子帶[ 2]: 43 43 44
子帶[ 3]: 44 46 45
子帶[ 4]: 45 47 47
子帶[ 5]: 46 48 47
子帶[ 6]: 47 49 51
子帶[ 7]: 47 49 49
子帶[ 8]: 49 48 48
子帶[ 9]: 51 50 46
子帶[10]: 49 49 49
子帶[11]: 48 50 48
子帶[12]: 50 48 48
子帶[13]: 48 48 50
子帶[14]: 47 49 50
子帶[15]: 50 50 49
子帶[16]: 48 49 49
子帶[17]: 49 50 49
子帶[18]: 50 50 50
子帶[19]: 51 51 50
子帶[20]: 51 49 50
子帶[21]: 53 53 51
子帶[22]: 53 50 50
子帶[23]: 49 49 48
子帶[24]: 51 51 53
子帶[25]: 53 57 53
子帶[26]: 57 53 56
子帶[27]: 53 53 55
子帶[28]: 54 53 54
子帶[29]: 55 54 55
子帶[30]: 56 57 54
========== 比特分配表 ==========
------ 聲道 1 ------
子帶[ 1]: 4
子帶[ 2]: 4
子帶[ 3]: 3
子帶[ 4]: 5
子帶[ 5]: 5
子帶[ 6]: 5
子帶[ 7]: 4
子帶[ 8]: 5
子帶[ 9]: 4
子帶[10]: 5
子帶[11]: 3
子帶[12]: 6
子帶[13]: 5
子帶[14]: 3
子帶[15]: 2
子帶[16]: 2
子帶[17]: 4
子帶[18]: 4
子帶[19]: 3
子帶[20]: 3
子帶[21]: 3
子帶[22]: 3
子帶[23]: 1
子帶[24]: 1
子帶[25]: 0
子帶[26]: 1
子帶[27]: 0
子帶[28]: 1
子帶[29]: 1
子帶[30]: 0
------ 聲道 2 ------
子帶[ 1]: 3
子帶[ 2]: 4
子帶[ 3]: 4
子帶[ 4]: 5
子帶[ 5]: 5
子帶[ 6]: 5
子帶[ 7]: 4
子帶[ 8]: 5
子帶[ 9]: 4
子帶[10]: 5
子帶[11]: 3
子帶[12]: 6
子帶[13]: 5
子帶[14]: 3
子帶[15]: 2
子帶[16]: 2
子帶[17]: 4
子帶[18]: 4
子帶[19]: 3
子帶[20]: 3
子帶[21]: 3
子帶[22]: 3
子帶[23]: 1
子帶[24]: 1
子帶[25]: 0
子帶[26]: 1
子帶[27]: 0
子帶[28]: 1
子帶[29]: 1
子帶[30]: 0
輸出比特率爲48 kbps時:
========== 基本信息 ==========
輸入文件:music.wav
輸出文件:music_48k.mp2
採樣頻率:44.1 kHz
輸出文件碼率:48 kbps
聲道數:2
目前觀測第 2 幀
本幀比特預算:1256 bits
========== 比例因子 ==========
------ 聲道 1 ------
子帶[ 1]: 33 35 35
子帶[ 2]: 44 41 41
子帶[ 3]: 47 46 46
子帶[ 4]: 47 46 45
子帶[ 5]: 46 44 47
子帶[ 6]: 50 47 48
子帶[ 7]: 46 49 49
子帶[ 8]: 47 48 48
------ 聲道 2 ------
子帶[ 1]: 34 34 36
子帶[ 2]: 43 43 44
子帶[ 3]: 44 46 45
子帶[ 4]: 45 47 47
子帶[ 5]: 46 48 47
子帶[ 6]: 47 49 51
子帶[ 7]: 47 49 49
子帶[ 8]: 49 48 48
========== 比特分配表 ==========
------ 聲道 1 ------
子帶[ 1]: 3
子帶[ 2]: 2
子帶[ 3]: 1
子帶[ 4]: 1
子帶[ 5]: 1
子帶[ 6]: 1
子帶[ 7]: 1
子帶[ 8]: 1
------ 聲道 2 ------
子帶[ 1]: 1
子帶[ 2]: 2
子帶[ 3]: 2
子帶[ 4]: 1
子帶[ 5]: 1
子帶[ 6]: 1
子帶[ 7]: 1
子帶[ 8]: 1
2. 噪聲
噪聲爲使用MATLAB產生的高斯白噪聲。
========== 基本信息 ==========
輸入文件:agwn.wav
輸出文件:agwn_192k.mp2
採樣頻率:44.1 kHz
輸出文件碼率:192 kbps
聲道數:1
目前觀測第 2 幀
本幀比特預算:5016 bits
========== 比例因子 ==========
------ 聲道 1 ------
子帶[ 1]: 24 23 22
子帶[ 2]: 25 23 25
子帶[ 3]: 24 27 24
子帶[ 4]: 24 26 25
子帶[ 5]: 24 25 24
子帶[ 6]: 27 25 25
子帶[ 7]: 25 24 24
子帶[ 8]: 25 24 24
子帶[ 9]: 25 22 25
子帶[10]: 25 25 25
子帶[11]: 23 26 27
子帶[12]: 25 24 24
子帶[13]: 24 23 24
子帶[14]: 23 24 24
子帶[15]: 26 24 25
子帶[16]: 24 25 23
子帶[17]: 23 25 24
子帶[18]: 25 23 23
子帶[19]: 24 25 25
子帶[20]: 23 26 24
子帶[21]: 24 25 23
子帶[22]: 24 25 23
子帶[23]: 23 23 24
子帶[24]: 26 25 24
子帶[25]: 23 25 24
子帶[26]: 24 23 26
子帶[27]: 25 24 25
子帶[28]: 24 26 23
子帶[29]: 23 25 23
子帶[30]: 26 24 22
========== 比特分配表 ==========
------ 聲道 1 ------
子帶[ 1]: 6
子帶[ 2]: 5
子帶[ 3]: 5
子帶[ 4]: 7
子帶[ 5]: 7
子帶[ 6]: 7
子帶[ 7]: 7
子帶[ 8]: 7
子帶[ 9]: 6
子帶[10]: 7
子帶[11]: 6
子帶[12]: 6
子帶[13]: 6
子帶[14]: 6
子帶[15]: 6
子帶[16]: 4
子帶[17]: 6
子帶[18]: 6
子帶[19]: 5
子帶[20]: 5
子帶[21]: 5
子帶[22]: 5
子帶[23]: 4
子帶[24]: 1
子帶[25]: 1
子帶[26]: 1
子帶[27]: 1
子帶[28]: 1
子帶[29]: 1
子帶[30]: 0
3. 樂音疊加噪聲
使用MATLAB在樂音波形上疊加高斯白噪聲。
========== 基本信息 ==========
輸入文件:music+agwn.wav
輸出文件:music+agwn_192k.mp2
採樣頻率:44.1 kHz
輸出文件碼率:192 kbps
聲道數:2
目前觀測第 2 幀
本幀比特預算:5016 bits
========== 比例因子 ==========
------ 聲道 1 ------
子帶[ 1]: 25 24 25
子帶[ 2]: 26 25 24
子帶[ 3]: 25 24 23
子帶[ 4]: 23 24 24
子帶[ 5]: 24 25 24
子帶[ 6]: 25 24 26
子帶[ 7]: 25 24 26
子帶[ 8]: 24 23 24
子帶[ 9]: 24 24 23
子帶[10]: 23 26 22
子帶[11]: 26 23 24
子帶[12]: 23 25 26
子帶[13]: 24 23 23
子帶[14]: 25 25 24
子帶[15]: 24 27 25
子帶[16]: 27 23 26
子帶[17]: 24 26 23
子帶[18]: 26 23 23
子帶[19]: 25 25 24
子帶[20]: 25 26 23
子帶[21]: 24 24 26
子帶[22]: 23 26 24
子帶[23]: 26 25 24
子帶[24]: 24 23 27
子帶[25]: 24 25 23
子帶[26]: 25 24 23
子帶[27]: 24 25 27
子帶[28]: 22 23 23
子帶[29]: 24 24 23
子帶[30]: 23 23 24
------ 聲道 2 ------
子帶[ 1]: 25 24 25
子帶[ 2]: 26 25 24
子帶[ 3]: 25 24 23
子帶[ 4]: 23 24 24
子帶[ 5]: 24 25 24
子帶[ 6]: 25 24 26
子帶[ 7]: 25 24 26
子帶[ 8]: 24 23 24
子帶[ 9]: 24 24 23
子帶[10]: 23 26 22
子帶[11]: 26 23 24
子帶[12]: 23 25 26
子帶[13]: 24 23 23
子帶[14]: 25 25 24
子帶[15]: 24 27 25
子帶[16]: 27 23 26
子帶[17]: 24 26 23
子帶[18]: 26 23 23
子帶[19]: 25 25 24
子帶[20]: 25 26 23
子帶[21]: 24 24 26
子帶[22]: 23 26 24
子帶[23]: 26 25 24
子帶[24]: 24 23 27
子帶[25]: 24 25 23
子帶[26]: 25 24 23
子帶[27]: 24 25 27
子帶[28]: 22 23 23
子帶[29]: 24 24 23
子帶[30]: 23 23 24
========== 比特分配表 ==========
------ 聲道 1 ------
子帶[ 1]: 3
子帶[ 2]: 3
子帶[ 3]: 3
子帶[ 4]: 4
子帶[ 5]: 4
子帶[ 6]: 3
子帶[ 7]: 3
子帶[ 8]: 4
子帶[ 9]: 3
子帶[10]: 3
子帶[11]: 2
子帶[12]: 3
子帶[13]: 1
子帶[14]: 3
子帶[15]: 1
子帶[16]: 1
子帶[17]: 1
子帶[18]: 2
子帶[19]: 2
子帶[20]: 1
子帶[21]: 1
子帶[22]: 1
子帶[23]: 1
子帶[24]: 0
子帶[25]: 0
子帶[26]: 0
子帶[27]: 0
子帶[28]: 0
子帶[29]: 0
子帶[30]: 0
------ 聲道 2 ------
子帶[ 1]: 3
子帶[ 2]: 3
子帶[ 3]: 3
子帶[ 4]: 3
子帶[ 5]: 4
子帶[ 6]: 3
子帶[ 7]: 3
子帶[ 8]: 4
子帶[ 9]: 3
子帶[10]: 3
子帶[11]: 2
子帶[12]: 3
子帶[13]: 1
子帶[14]: 3
子帶[15]: 1
子帶[16]: 1
子帶[17]: 1
子帶[18]: 2
子帶[19]: 2
子帶[20]: 1
子帶[21]: 1
子帶[22]: 1
子帶[23]: 0
子帶[24]: 0
子帶[25]: 0
子帶[26]: 0
子帶[27]: 0
子帶[28]: 0
子帶[29]: 0
子帶[30]: 0