基于vhdl简易音乐播放器设计说明书.docx
《基于vhdl简易音乐播放器设计说明书.docx》由会员分享,可在线阅读,更多相关《基于vhdl简易音乐播放器设计说明书.docx(38页珍藏版)》请在冰豆网上搜索。
基于vhdl简易音乐播放器设计说明书
EDA技术实用教程
课程设计
简易音乐播放器
电子12-1
1206040124
简易音乐播放器设计
1.MIDI概述
MIDI(MusicalInstrumentDigitalInterface)乐器数字接口,是20世纪80年代初为解决电声乐器之间的通信问题而提出的。
MIDI是编曲界最广泛的音乐标准格式,可称为“计算机能理解的乐谱”。
它用音符的数字控制信号来记录音乐。
一首完整的MIDI音乐只有几十KB大,而能包含数十条音乐轨道。
MIDI应用也比较广泛,电视晚会的音乐编导可以用MIDI功能辅助音乐创作,或按MIDI标准生成音乐数据传播媒介,或直接进行乐曲演奏。
如果在计算机上装备了高级的MIDI软件库,可将音乐的创作、乐谱的打印、节目编排、音乐的调整、音响的幅度、节奏的速度、各声部之间的协调、混响由MIDI来控制完成。
利用MIDI技术将电子合成器、电子节奏机(电子鼓机)和其他电子音源与序列器连接在一起即可演奏模拟出气势雄伟、音色变化万千的音响效果,又可将演奏中的多种按键数据存储起来,极大的改善了音乐演奏的能力和条件。
2.工作原理
MIDI音乐是Windows下的一种合成音乐,由于它通过记谱的方式来记录一段音乐。
因此与wave音乐相比,它可以极大的减少存储容量。
MIDI音乐的基本原理为:
组成乐曲的每一个音符的频率值(音调)及其持续的时间(音长)是乐曲能连续演奏的两个基本数据,因此只要控制输出到扬声器的激励信号频率的高低和每一个频率信号持续时间,就可以使扬声器发生连续的乐曲。
图1是歌曲《生日快乐歌》开头一句的简谱。
由图1可知,该乐典涉及:
中音5,6,7;高音1,2,3,4,5。
以此为例下面介绍在本音乐发生器芯片中音乐的形成过程。
前两个音符为中音5,1/16音符,它对应的编码为1000,所占的脉冲个数为2,这样逐个将以上的简谱翻译成代码如下:
|100010001001100110001000|101110111010101010101010|
|100010001001100110001000|110011001011101110111011|
|100010001111111111011101|101110111010101010011001|
|111011101101110110111011|110011001011101110111011|
图1《生日快乐歌》歌谱
在节奏时钟脉冲的控制下,将每个代码所对应的分频系数逐一赋给基频,得到对应的音调,这样连续起来就形成一段美妙的音乐。
本设计的关键是要准确地产生音乐中各音符所对应的频率信号,并根据乐曲要求按节拍输出。
为了减少系统复杂性,本设计根据可变模值计数器的原理,按照乐曲要求定时改变计数器的预置数,即可产生乐曲所需要的频率信号。
芯片原理框图如图2所示。
图2中节拍控制电路产生节拍定时信号;音符产生电路按节拍要求产生乐曲所需要的音符;预值数产生电路受音符控制,产生该音符频率相对应的预置数,送计数器的置入数据输入端。
音符频率发生器根据不同的预置数产生相应的频率信号,从而完成乐曲的演奏功能。
图2播放器原理
3.音乐编码模块
此模块包括节拍控制电路和音符产生电路。
节拍控制电路以乐曲中最短音符的节拍为基准,产生乐曲所需要的全部节拍。
因为乐曲《生日快乐歌》中最短音符为1/4节拍,全曲共有48个1/4节拍,故节拍控制器至少需要产生48个有效状态。
考虑到一遍演奏完需要间隔时间,所以选定节拍控制计数器CNT1的计数状态为48+4个,其中间隔时间为4个有效状态。
本例要求演奏时能循环进行,因此需要另外设置一个时长计数器,当乐曲演奏完成时,保证能自动从头开始演奏。
音符产生电路采用查找表形式.在节拍控制产生电路的节拍信号作用下,按乐曲中音符持续时间的长短输出相应音符名称。
以乐曲中前两个音节为例,其音符输出查找表如表1所示。
4.音调发生模块
此模块包括预值数产生电路和频率发生器。
预值数产生电路设计采用查找表形式,按照音符的频率要求产生相应的预置数。
根据可变模值计数器的设计原理及音符的分频系数,可计算出乐曲《生日快乐歌》中各音符的预置数如表2所示。
表2音频的分频和预置数
频率发生器由可变模值计数器实现.由于系统要求产出的信号频率较高,因此选用2MHz高频脉冲信号作为可变模值计数器的计数脉冲。
此片段内各音阶频率及相应的分频如表3所示。
为了减少输出的偶次谐波分量,最后输出到扬声器的波形应为对称方波,考虑到输出信号是脉冲极窄的脉冲式信号,为了有利于驱动扬声器,可以在到达扬声器之前,有一个二分的分频器,或在计数器输出端外加一个D触发器也可以均衡占空比。
当然,如果输出到扬声器的信号采用正弦波代替对称方波将会有更好的效果。
表3音符与频率对照表
由于最大的分频系数为5102,故采用13位十二进制计数器已能满足分频要求。
在表3中除给出了分频比以外,还给出了相应于各个音节频率时计数器不同的初始值。
对于不同的分频系数,只要加载不同的初始值即可。
采用加载初始值而不将分频输出译码反馈,一个常用技巧。
表中“0”表示休止符。
对于乐曲的休止符。
只要将分频系数设为0,即初始值为213-1=8191,此时扬声器将不会发声。
5.顶层文件设计
顶层文件采用原理图设计,根据图1所示原理框图,可设计出MIDI音乐,发生器顶层原理如图3所示。
为了方便设计,图3中将节拍控制电路和音符产生电路设计在同一模块中,称为TONE模块。
音调发生器电路称为FPQ模块,彩灯控制电路称为LIGH模块。
图3顶层远离
6.底层文件
TONE模块中的CLK为4Hz信号输入端,SEL[3…0]为音符输出端,其输出用于驱动FPQ和LIGHT模块。
图4为其时序仿真,其中SEL为各个音符的二进制编码。
从图4可以看出,仿真结果和设计要求一致。
前两个脉冲SEL输出为1000,即为中音5的二进制编码,第三第四个脉冲下SEL为1001,对应中音6,依次下去,第五第六个脉冲下SEL为1000,对应中音5,第七第八个脉冲下SEL为1011,对应高音1,后面四个脉冲下SEL为1010对应中音7。
COUNT为节拍控制计数器。
图4音乐编码器仿真
FPQ模块中的CLKM为2MHz输入端,MUS为音调输出端。
图5为其时序仿真,在这里只对音符中音5仿真,此时其编码为1000,NUM为其分频系数1276。
当CT计数到1276时,MUS就输出计数脉冲,其效果就是频率784的信号。
图5音调发生器仿真
7.部分代码
libraryieee;
useieee.std_logic_1164.all;
useieee.std_logic_unsigned.all;
useieee.std_logic_arith.all;
entityzy4668_music1is
port(clk:
instd_logic;
huifang:
instd_logic;
qiege:
instd_logic;
xuhuan:
instd_logic;
zanti:
instd_logic;
xuan:
instd_logic_vector(1downto0);
index:
outstd_logic_vector(3downto0));
endzy4668_music1;
architecturebehavofzy4668_music1is
subtypewordisintegerrange0to15;
typememoryisarray(0to565)ofword;
signalrom:
memory;
signalclk_4Hz:
std_logic;
signalclk_cnt:
integerrange0to249;
signaladr:
integerrange0to600;
signalsar:
integerrange0to600;
signalsar1:
integerrange0to600;
begin
process(clk,zanti)
begin
ifzanti='1'then
ifclk'eventandclk='1'then
ifclk_cnt=249then
clk_cnt<=0;clk_4Hz<='1';
else
clk_cnt<=clk_cnt+1;clk_4Hz<='0';
endif;
endif;
endif;
endprocess;
process(clk_4Hz,xuan,zanti,xuhuan,qiege,huifang)
begin
ifzanti='1'then
ifxuan="00"andqiege='0'then
adr<=416;sar<=558;sar1<=416;
elsifxuan="01"andqiege='0'then
adr<=0;sar<=138;sar1<=0;
elsifxuan="10"andqiege='0'then
adr<=139;sar<=279;sar1<=139;
elsifxuan="11"andqiege='0'then
adr<=280;sar<=415;sar1<=280;
else
ifclk_4hz'eventandclk_4hz='1'then
ifhuifang='1'then
ifxuhuan='1'then
ifadr=sarthenadr<=sar1;
elseadr<=adr+1;
endif;
else
ifadr=558thenadr<=0;
elseadr<=adr+1;
endif;
ifadr>415thensar<=558;sar1<=416;
elsifadr>279thensar<=415;sar1<=279;
elsifadr>138thensar<=279;sar1<=139;
elsesar<=138;sar1<=0;
endif;
endif;
else
ifadr=sar1thenadr<=sar1;
elseadr<=adr-1;
endif;
endif;
endif;
endif;
endif;
endprocess;
index<=conv_std_logic_vector(rom(adr),4);
rom(0)<=3;rom
(1)<=3;rom
(2)<=3;rom(3)<=3;
rom(4)<=5;rom(5)<=5;rom(6)<=5;rom(7)<=6;
rom(8)<=8;rom(9)<=8;rom(10)<=8;rom(11)<=9;
rom(12)<=6;rom(13)<=8;rom(14)<=5;rom(15)<=5;
rom(16)<=12;rom(17)<=12;rom(18)<=12;rom(19)<=15;
rom(20)<=13;rom(21)<=12;rom(22)<=10;rom(23)<=12;
rom(24)<=9;rom(25)<=9;rom(26)<=9;rom(27)<=9;
rom(28)<=9;rom(29)<=9;rom(30)<=9;rom(31)<=0;
rom(32)<=9;rom(33)<=9;rom(34)<=9;rom(3