十段图示均衡器实验报告

更新时间:2023-08-28 15:19:01 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

十段图示均衡器实验报告

班级:10011107 学号:2011302542 姓名:孔莹莹

一、 实验目的:

均衡器是被广泛应用的音效增强手段,也是实现低音增强、高频补偿、人声清晰度增强等音效的基础。本作业在实现音频 I/O(作业一)的基础上,实现一个具有 GUI 界面的十段均衡器小软件,实时对播放音乐进行音效调整。

二、 实验要求:

本实验要求使用 C/C++语言编程实现一个具有 GUI 界面的图示十段音频均衡器(参考图 3 和演示视频 eq.avi),系统输入为采样率 44.1KHz、单声道的 WAV格式音频文件(如本实验给的 song_mono.wav),输出为经过均衡之后 PCM 数据流,通过声卡播放出来。通过调整界面上的滑动杆或者选择预设效果,实时调整音效。

三、 实验原理:

图示均衡器的原理很简单。图示均衡器由一个低通滤波器,一个高通滤波器和若干带通滤波器并联而成的滤波器组构成。这些构成均衡器的滤波器中心频率和带宽都是不变的,每个滤波器后接一个增益调节器。总输出为各个滤波器的加权求和。用户通过调节每个滤波器的输出增益,来改变均衡器的整体频响。图示均衡器的整体实现框图,如图2 所示

对于10 段图示均衡器,1 倍频程图示均衡器的10 个中心频点为:31.5Hz, 63Hz,125Hz,250Hz, 500Hz, 1000Hz, 2000Hz,4000Hz,8000Hz,16000Hz, 依据这些频点按倍频程公式计算各个频段的边界频率,然后设计各频段的滤波器,然后级联增益调节器再并接起来就构成了10 段图示均衡器。

采用二阶 IIR 带通滤波器级联实现十段图示均衡器。带通滤波器主要性能指标包括中心频率、带宽、增益、品质因子等,现简介如下:

中心频率(CF):通带滤波器功率谱的值达到最大值时对应的频率。

带宽(BW):中心频率两边功率衰减 3dB 时,对应的两个不同频率,分别为上、下截止频率,上、下截止频率之差为带宽。

增益(G):均衡器对于各种音效的实现依靠的最重要指标为增益曲线 ,一般以分贝为单位表示。

品质因子(Q):中心频率与带宽的比值,用来表征滤波器的锐度。

音乐风格

Default

Club

Dance

Full Buss

Full Treble

Pope

Rock

Soft

Large Hall

Party 预设增益 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } { 0, 0, 0, 1, 2, 3, 3, 2, 1, 0 } { 9, 8, 5, 2, 1, 0, -3, -4, -3,0 } { 8, 8, 8, 7, 4, 0, -3, -5,-7,-9 } { -9, -8, -7, -6, -3, 1, 5, 8, 10, 12 } { -2, -1, 0, 2, 3, 2, 0, -2, -2, -1 } { 6, 5, 2, -2, -5, -2, 0, 3, 5, 6 } { 2, 1, 0, 0, -1, 0, 1, 2, 3, 4 } { 8, 7, 6, 3, 2, 0, -1, -2, -1, 0 } { 4, 4, 3, 2, 0, 0, 0, 0, 0, 4 }

四、 实验主要代码:

//音乐风格的预设增益

int PreEft[18][10]={0,0,0,0,0,-1,-2,-4,-6,-9,

0,0,0,1,2,3,3,2,1,0,

9,8,5,2,1,0,-3,-4,-3,0,

0,0,0,0,0,0,0,0,0,0,

8,8,8,7,4,0,-3,-5,-7,-9,

7,6,4,1,-3,-2,-1,2,6,9,

-9,-8,-7,-6,-3,1,5,8,10,12,

1,5,7,3,-2,-1,0,3,6,10,

8,7,6,3,2,0,-1,-2,-1,0,

-4,-3,-1,0,2,3,3,2,1,0,

4,4,3,2,0,0,0,0,0,4,

-2,-1,0,2,3,2,0,-2,-2,-1,

0,0,0,-1,-3,0,2,2,1,0,

6,5,2,-2,-5,-2,0,3,5,6,

-1,-2,-3,-2,0,1,2,3,4,5,

2,1,0,0,-1,0,1,2,3,4,

1,1,1,1,0,-1,-2,-2,0,3,

3,2,1,0,-3,-2,-1,1,3,4};

int CEqualizer::UseEQ(EQPARAM *param, unsigned char *Sig, unsigned char * OutSig, long ILen)

{

unsigned long Hband=(unsigned long)(3*param->Fs/8);

double * bandpow=(double*)malloc(param->wbandlen*sizeof(double)); long i,k,len,level=-1;

for (i=9;i>=0;i--)

{

if (CenBand[i]<Hband)

{level=i;break;}

}

if ((level<1)||((level+1)>param->wbandlen)) return ERR_PARAMERR; if (level==1) return ERR_NOERR;

InitFilterBank(level);

for (i=0;i<param->wbandlen;i++) bandpow[i]=pow(10,(param->wband[i]/20));

double *tSig1=NULL;

double *tSig2=NULL;

if (param->bitpersmp==16)

{

short * sig16=NULL;

if(param->nchn==2)

{

len=ILen>>2;

if(NULL==(tSig1=(double*)malloc(sizeof(double)*len))) return ERR_INSURMEM;

if(NULL==(tSig2=(double*)malloc(sizeof(double)*len))) return ERR_INSURMEM;

sig16=(short*)Sig;k=0;

for (i=0;i<len;i++)

{tSig1[i]=sig16[k++]/32768.;tSig2[i]=sig16[k++]/32768.;} //channel1

WaveDec(tSig1,len);

for (i=0;i<level+1;i++)//add weight

{

k=Lb[i];

while (k<=Le[i]) {C[k]*=bandpow[i];k++;}

}

WaveRec(tSig1,len);

//channel2

WaveDec(tSig2,len);

for (i=0;i<level+1;i++)//add weight

{

k=Lb[i];

while (k<=Le[i]) {C[k]*=bandpow[i];k++;}

}

WaveRec(tSig2,len); //write back to OutSig sig16=(short*)OutSig;k=0; for (i=0;i<len;i++) { if (tSig1[i]>1) sig16[k++]=32767; else if (tSig1[i]<-1) sig16[k++]=-31768; else sig16[k++]=(short)(tSig1[i]*32768); if (tSig2[i]>1) sig16[k++]=32767; else if (tSig2[i]<-1) sig16[k++]=-31768; else sig16[k++]=(short)(tSig2[i]*32768); } } else if(param->nchn==1) { len=ILen>>1; if(NULL==(tSig1=(double*)malloc(sizeof(double)*len))) return ERR_INSURMEM; sig16=(short*)Sig; for (i=0;i<len;i++) {tSig1[i]=sig16[i]/32768.;} //channel1 WaveDec(tSig1,len); for (i=0;i<level+1;i++)//add weight { k=Lb[i]; while (k<=Le[i]) {C[k]*=bandpow[i];k++;} } WaveRec(tSig1,len); //write back to OutSig sig16=(short*)OutSig; for (i=0;i<len;i++) { if (tSig1[i]>1) sig16[i]=32767; else if (tSig1[i]<-1) sig16[i]=-31768; else sig16[i]=(short)(tSig1[i]*32768); } } else return ERR_PARAMERR; } else if (param->bitpersmp==8) {

if(param->nchn==2)

{

len=ILen>>1;

if(NULL==(tSig1=(double*)malloc(sizeof(double)*len))) return ERR_INSURMEM;

if(NULL==(tSig2=(double*)malloc(sizeof(double)*len))) return ERR_INSURMEM;

k=0;

for (i=0;i<len;i++)

{tSig1[i]=(Sig[k++]-128)/128.;tSig2[i]=(Sig[k++]-128)/128.;} //channel1

WaveDec(tSig1,len);

for (i=0;i<level+1;i++)//add weight

{

k=Lb[i];

while (k<=Le[i]) {C[k]*=bandpow[i];k++;}

}

WaveRec(tSig1,len);

//channel2

WaveDec(tSig2,len);

for (i=0;i<level+1;i++)//add weight

{

k=Lb[i];

while (k<=Le[i]) {C[k]*=bandpow[i];k++;}

}

WaveRec(tSig2,len);

//write back to OutSig

k=0;

for (i=0;i<len;i++)

{

if (tSig1[i]>1) OutSig[k++]=255;

else if (tSig1[i]<-1) OutSig[k++]=0;

else OutSig[k++]=(unsigned char)(tSig1[i]*128+128);

if (tSig2[i]>1) OutSig[k++]=255;

else if (tSig2[i]<-1) OutSig[k++]=0;

else OutSig[k++]=(unsigned char)(tSig2[i]*128+128);

// OutSig[k++]=(unsigned char)(tSig1[i]*128+128); // OutSig[k++]=(unsigned char)(tSig2[i]*128+128); }

}

else if(param->nchn==1)

{

len=ILen;

if(NULL==(tSig1=(double*)malloc(sizeof(double)*len))) return ERR_INSURMEM;

for (i=0;i<len;i++)

{tSig1[i]=(Sig[i]-128)/128;}

//channel1

WaveDec(tSig1,len);

for (i=0;i<level+1;i++)//add weight

{

k=Lb[i];

while (k<=Le[i]) {C[k]*=bandpow[i];k++;}

}

WaveRec(tSig1,len);

//write back to OutSig

for (i=0;i<len;i++)

{

if (tSig1[i]>1) OutSig[i]=255;

else if (tSig1[i]<-1) OutSig[i]=0;

else OutSig[i]=(unsigned char)(tSig1[i]*128+128); // OutSig[i]=(unsigned char)(tSig1[i]*128+128);

}

}

else

return ERR_PARAMERR;

}

free(bandpow);

if(tSig1!=NULL) free(tSig1);

if(tSig2!=NULL) free(tSig2);

return ERR_NOERR;

}

//启用均衡

void CEQDlg::OnBtnset() //启用均衡

{

// TODO: Add your control notification handler code here isset=true;

CScrollBar* pSB=(CScrollBar*) GetDlgItem(IDC_SCR1);

pSB->EnableScrollBar(ESB_ENABLE_BOTH );

pSB=(CScrollBar*) GetDlgItem(IDC_SCR2);

pSB->EnableScrollBar(ESB_ENABLE_BOTH );

pSB=(CScrollBar*) GetDlgItem(IDC_SCR3);

pSB->EnableScrollBar(ESB_ENABLE_BOTH );

pSB=(CScrollBar*) GetDlgItem(IDC_SCR4);

pSB->EnableScrollBar(ESB_ENABLE_BOTH );

pSB=(CScrollBar*) GetDlgItem(IDC_SCR5);

pSB->EnableScrollBar(ESB_ENABLE_BOTH );

pSB=(CScrollBar*) GetDlgItem(IDC_SCR6);

pSB->EnableScrollBar(ESB_ENABLE_BOTH );

pSB=(CScrollBar*) GetDlgItem(IDC_SCR7);

pSB->EnableScrollBar(ESB_ENABLE_BOTH );

pSB=(CScrollBar*) GetDlgItem(IDC_SCR8);

pSB->EnableScrollBar(ESB_ENABLE_BOTH );

pSB=(CScrollBar*) GetDlgItem(IDC_SCR9);

pSB->EnableScrollBar(ESB_ENABLE_BOTH );

pSB=(CScrollBar*) GetDlgItem(IDC_SCR10);

pSB->EnableScrollBar(ESB_ENABLE_BOTH );

pSB=(CScrollBar*) GetDlgItem(IDC_SCRG);

pSB->EnableScrollBar(ESB_ENABLE_BOTH );

if(isset)

{

for (int i=0;i<10;i++) bandpow[i]+=m_editg;

mwavefile.SetEQ(bandpow,10);

}

}

//禁用均衡

void CEQDlg::OnBtnclose() //禁用均衡

{

// TODO: Add your control notification handler code here isset=false;

CScrollBar* pSB=(CScrollBar*) GetDlgItem(IDC_SCR1);

pSB->EnableScrollBar(ESB_DISABLE_BOTH);

pSB=(CScrollBar*) GetDlgItem(IDC_SCR2);

pSB->EnableScrollBar(ESB_DISABLE_BOTH);

pSB=(CScrollBar*) GetDlgItem(IDC_SCR3);

pSB->EnableScrollBar(ESB_DISABLE_BOTH);

pSB=(CScrollBar*) GetDlgItem(IDC_SCR4);

pSB->EnableScrollBar(ESB_DISABLE_BOTH);

pSB=(CScrollBar*) GetDlgItem(IDC_SCR5);

pSB->EnableScrollBar(ESB_DISABLE_BOTH);

pSB=(CScrollBar*) GetDlgItem(IDC_SCR6);

pSB->EnableScrollBar(ESB_DISABLE_BOTH);

pSB=(CScrollBar*) GetDlgItem(IDC_SCR7);

pSB->EnableScrollBar(ESB_DISABLE_BOTH);

pSB=(CScrollBar*) GetDlgItem(IDC_SCR8);

pSB->EnableScrollBar(ESB_DISABLE_BOTH);

pSB=(CScrollBar*) GetDlgItem(IDC_SCR9);

pSB->EnableScrollBar(ESB_DISABLE_BOTH);

pSB=(CScrollBar*) GetDlgItem(IDC_SCR10);

pSB->EnableScrollBar(ESB_DISABLE_BOTH);

pSB=(CScrollBar*) GetDlgItem(IDC_SCRG);

pSB->EnableScrollBar(ESB_DISABLE_BOTH);

mwavefile.StopEQ();

}

//归零

void CEQDlg::OnBtnzero() //归零

{

// TODO: Add your control notification handler code here if (isset)

{

CScrollBar* pSB=(CScrollBar*) GetDlgItem(IDC_SCR1);

pSB->SetScrollPos(0);

pSB=(CScrollBar*) GetDlgItem(IDC_SCR2);

pSB->SetScrollPos(0);

pSB=(CScrollBar*) GetDlgItem(IDC_SCR3);

pSB->SetScrollPos(0);

pSB=(CScrollBar*) GetDlgItem(IDC_SCR4);

pSB->SetScrollPos(0);

pSB=(CScrollBar*) GetDlgItem(IDC_SCR5);

pSB->SetScrollPos(0);

pSB=(CScrollBar*) GetDlgItem(IDC_SCR6);

pSB->SetScrollPos(0);

pSB=(CScrollBar*) GetDlgItem(IDC_SCR7);

pSB->SetScrollPos(0);

pSB=(CScrollBar*) GetDlgItem(IDC_SCR8);

pSB->SetScrollPos(0);

pSB=(CScrollBar*) GetDlgItem(IDC_SCR9);

pSB->SetScrollPos(0);

pSB=(CScrollBar*) GetDlgItem(IDC_SCR10);

pSB->SetScrollPos(0);

UpdateData();

bandpow[0]=m_edit1=0;

bandpow[1]=m_edit2=0;

bandpow[2]=m_edit3=0;

bandpow[3]=m_edit4=0;

bandpow[4]=m_edit5=0;

bandpow[5]=m_edit6=0;

bandpow[6]=m_edit7=0;

bandpow[7]=m_edit8=0;

bandpow[8]=m_edit9=0;

bandpow[9]=m_edit10=0;

m_editg=0;

UpdateData(FALSE);

if(isset) mwavefile.SetEQ(bandpow,10);

}

}

//选择下拉效果菜单

void CEQDlg::OnSelchangePresent() //效果选择下拉框

{

isset=true;

int ix=m_PresentEf.GetCurSel();

bandpow[0]=m_edit1=PreEft[ix][0];

bandpow[1]=m_edit2=PreEft[ix][1];

bandpow[2]=m_edit3=PreEft[ix][2];

bandpow[3]=m_edit4=PreEft[ix][3];

bandpow[4]=m_edit5=PreEft[ix][4];

bandpow[5]=m_edit6=PreEft[ix][5];

bandpow[6]=m_edit7=PreEft[ix][6];

bandpow[7]=m_edit8=PreEft[ix][7];

bandpow[8]=m_edit9=PreEft[ix][8];

bandpow[9]=m_edit10=PreEft[ix][9];

m_scr1=-m_edit1;

m_scr2=-m_edit2;

m_scr3=-m_edit3;

m_scr4=-m_edit4;

m_scr5=-m_edit5;

m_scr6=-m_edit6;

m_scr7=-m_edit7;

m_scr8=-m_edit8;

m_scr9=-m_edit9;

m_scr10=-m_edit10;

UpdateData(FALSE);

if(isset)

{

for (int i=0;i<10;i++) bandpow[i]+=m_editg;

mwavefile.SetEQ(bandpow,10);

}

// mwavefile.SetEQ(bandpow,10);

}

五、 实验效果测试

音质评价采用主观测听的方式进行,预设 10 种均衡风格,从 3 个维度进行 音质评价,即低频、中频、高频。以下是对这 3 个维度的详细描述:

低频:给人形成的主观听感包括丰满度、柔和度、清晰度等。测听重点是声 音要有通透感,不能发闷,感觉厚但不能混,有弹性。

中频:给人形成的主观听感包括圆润度、真实度、力度感等。测听重点是人 声部分,要有甜美、温暖的感觉,吉他部分不能干瘪,不刺耳,音色亮但不尖。

高频:给人形成的主观听感包括清晰度、通透感等。测听重点是声音通透, 不发闷,不尖,有余音袅袅的味道。

六、 实验总结

实验刚开始时,由于对十段均衡器的原理不是很明白,做得比较纠结,查阅了有关数字信号的书籍了解了如何改变增益和控制各个典型频率来达到调节音效的目的。这次的GUI界面按钮比较多,对MFC编程不是很熟悉,导致出现了很多错误,在同学的帮助下都一一解决了。

本文来源:https://www.bwwdw.com/article/5ahi.html

Top