最新c语言发声程序.docx
- 文档编号:6966225
- 上传时间:2023-01-13
- 格式:DOCX
- 页数:13
- 大小:20.66KB
最新c语言发声程序.docx
《最新c语言发声程序.docx》由会员分享,可在线阅读,更多相关《最新c语言发声程序.docx(13页珍藏版)》请在冰豆网上搜索。
最新c语言发声程序
字号:
大中小
c语言经典教程:
发声技术
问题:
乐谱的1、2、3、4、5、6、7,加上高低音可以谱出动听的曲子,请编写程
序,使计算机能够播放歌曲。
[分析]
播放歌曲意味着让计算机发声,声音从PC机内的扬声器发出,所以这个问题将与
硬件扬声器电路有关。
[解答]
解决这一编程问题,让我们首先简单了解一下计算机发声的原理。
在PC机的系统板上装有定时与计数器8253芯片,还有8255可编程并行接口芯片,由它们组成的硬件电路
可用来产生PC机内扬声器的声音,对于286、386、486、586等PC微机,由于采用了超大
规模集成电路,因而看不到这些芯片,它们均集成在外围电路芯片上了。
当我们操作计算机时,常常听到的发声,就是由软件控制这些电路而产生的。
声音的
长短和音调的高低,均可由程序进行控制。
在扬声器电路中,定时器的频率决定了扬声器发
音的频率,所以可通过设定定时器电路的频率来使扬声器发出不同的声音。
对定时器电路进
行频率设定时,首先对其命令寄存器(口地址为0x43)写命令字,如写入 0xb6,这可用
outporb(0x43,0xb6);来实现,则表示选择该定时器的第二个通道,计数频率先送低8位(二
进制),后送高8位。
接着用口地址0x42送频率计数值,先送低8位,后送高8位,即用
outportb(0x42,低8位频率计数值)和outportb(0x42,高8位频率计数值)来实现。
通过这两
步使定时器电路产生一系列方波信号,此信号是否能推动扬声器发音,还要看由8255产生
的门控信号和送数信号是否为1,而它们也可编程,口地址为0x61。
为了不影响8255口地
址61H中的其他高位,应先输入口地址6lH的现有值bits,即用bits=inportb(0x61)来实现,
然后就可用outportb(0x61,bits|3)来允许发声,而用outportb(0x61,bits&0xfc)来禁止发声,
且不改变8255其它位原来的值,关于这方面的详细内容可以参阅IBMPC/XT接口技术方面
书籍有关内容。
5.1声音函数
编写音乐程序播放歌曲,最简单的方法是可以直接使用TURBOC在dos.h中提供的有
关发声的函数sound()和nosound()。
sound()函数用于产生声音,其原型如下:
voidsound(unsignedfrequency);
该函数的入口参数为扬声器要产生声音的频率。
与sound()函数相反,nosound()函数用于关闭扬声器,其原型为:
voidnosound(void);
该函数没有入口和出口参数,它只是简单地把口地址61H中的低2位清0。
在利用函数sound产生指定频率的声音后,一般要过一段时间后再调用函数nosound关
闭扬声器,这样我们才能清楚地听到一个声音。
如果扬声器刚打开就关闭,我们是很难听到
一个声音的。
某个频率的声音延续时间的长短是重要的,它将直接影响音响效果。
这需要使
用TURBOC提供了专门的延时函数delay,其原型说明如下:
voiddelay(unsignedmilliseconds);
该函数中断程序的执行,中断的时间由milliseconds指定。
例程3-36:
该程序每间隔10000millisecondspc扬声器发出不同频率的声音,直到频率大于
5000hz。
#include
main()
{
intfreq;
for(freq=50;freq<5000;freq+=50)
{
sound(freq);
delay(10000);
}
nosound();
}
如果不能使用上述现成的函数sound()和nosound(),当然我们也可以采用上节中的方法,
用 I/O 接口的输入输出函数,自己编写产生声音和关闭声音的函数。
下面可供参考的函数
SOUND()与TURBOC提供的产生声音函数sound()的算法类似:
首先函数SOUND()中使用
了一个由一个整数和两个字符组成的联合,其目的在于方便地把一个16位数分解成两个8
位数。
为了打开扬声器,需要把口地址61H的低2位置位,但又不能影响其他高位,为此,
先输入口地址61H中的现有值,与3逻辑或后再输出到口地址61H。
voidSOUND(unsignedfrequency)
{
union {
unsigneddivisor;
unsignedcharc[2];
}tone;/* 定义由—个整数和两个字符组成的联合*/
tone.divisor=119328/frequency;/* 计算该频率对应的定时器计数值 */
outportb(0x43,0xb6); /* 通知定时器采用新的计数*/
outportb(0x42,tone.c[0]);/*计数低字节先送到定时器*/
outportb(0x42,tone.c[1]); /* 计数高字节后送到定时器*/
outportb(0x61,inportb(0x61)|3); /* 使定时器到喇叭的输出有效 */
}
如下供参考的函数NOSOUND(),为了不影响口地址61H中的其他高位,应先输入口地
址6lH的现有值.在屏蔽掉低2位后再输出到口地址61H。
voidNOSOUND(void)
{
outportb(0x61,inportb(0x61)&0xfc)); /* 使定时器到喇叭的输出无效 */
}
5.2计算机乐谱
表3-18是频率与音阶的对照表。
我们可以通过该表编制出自己的驱动程序。
编制乐谱
程序一般在原乐谱的基础上添加一些控制字符来完成。
如:
。
。
。
。
。
。
。
。
_11176323262
就是孟庭苇演唱的“羞答答的玫瑰静俏俏地开”的第一句歌词的乐谱。
在计算机中可以表述为:
600H10.5H10.5H10.5M70.5M61H31H20.5H30.5H20.5M60.5H22
第一个为音长基准,一般为300,600,900,1200。
后面字H1表示高音的1,音阶的
设置如下:
最高音:
在音符前加“E”;
高音:
在音符前加“计”;
中音:
在音符前加“M”;
低音:
在音符前加“L”;
再后面的字为节拍数,其中的0.5表示节拍数,每个音的音长=音长基数×\u33410X拍数,如
第一个“1”的音长为600×0.5=300。
表3-18频率与音阶的对照表
低音
1
2
3
4
5
6
7
频率
131
147
165
176
196
220
247
中音
1
2
3
4
5
6
7
频率
262
296
330
349
392
440
494
高音
1
2
3
4
5
6
7
频率
523
587
659
699
784
880
988
最高音
1
2
3
4
5
6
7
频率
1047
1175
1319
1397
1568
1760
1976
知道了这些知识,就容易编制—个乐谱驱动程序。
思路是将各个频率存储在一个二维数
组中,根据音阶字符、音符和节拍数,得到发音的音长,使用sound函数发音,使用delay
函数控制。
5.3问题实现
5.3.1 调用sound()和unsound()
下面的程序(例程3-37)先开辟两个数组freq[96]和dely[96]分别用于存储声音的频
率和延时。
采用图形方式,利用printtext()函数在屏幕上分别显示字符串Welcome!
","Please
pressanykeytostart......","Enjoyyourself!
”,"Pressanykeytoend!
" 和 "Thankyou!
Bye
Bye......"
printtext()定义如下:
voidprinttext(unsignedchar*temp[],inti)
{
setcolor(4); //设置颜色为red
settextstyle(TRIPLEX_FONT,HORIZ_DIR,3);//设置字符的字体,方向和大小
outtextxy(100,40+i*50,temp[i]); //显示字符串
}
另外,在此程序中还调用了conio.h 中的函数kbhit(),用于判断是否有键按下,当没有键按下
时返回0。
/*例程3-37*/
#include
#include
voidprinttext(unsignedchar*temp[],inti); // 用于在屏幕上显示字符串
main()
{
inti,graphdriver,graphmode;
unsignedchar*temp[4];
intfreq[96]={784,660,588,660,523,523,
588,494,440,523,392,392,
330,392,440,523,784,440,523,392,
784,1048,880,784,660,784,588,588,
588,660,494,440,392,440,523,588,
330,523,440,392,440,523,392,392,
660,784,494,588,440,523,392,392,
330,392,330,392,392,440,494,588,440,440,392,440,
523,588,784,660,588,660,588,523,440,392,
330,523,440,523,440,392,330,392,440,523,
392,392,660,784,588,660,588,523,494,440,784,784};
intdely[96]={25,50,12,12,50,50,
25,50,12,12,50,50,
50,38,12,38,12,12,12,25,
38,12,12,12,12,12,50,50,
38,12,25,25,38,12,25,25,
25,25,12,12,12,12,50,50,
38,12,25,25,12,12,50,25,
12,12,12,12,12,12,12,12,50,25,12,12,
38,12,25,25,25,12,12,25,12,12,
50,50,12,12,12,12,12,12,12,12,
50,25,12,12,12,12,12,12,25,25,50,50};
graphdriver=DETECT;
graphmode=0;
temp[0]="Welcome!
";
temp[1]="Pleasepressanykeytostart......";
temp[2]="Enjoyyourself!
";
temp[3]="Pressanykeytoend!
";
temp[4]="Thankyou!
ByeBye......";
initgraph(&graphdriver,&graphmode,""); //系统初始化
cleardevice(); //清除屏幕
settextjustify(LEFT_TEXT,CENTER_TEXT); //设置字符排列方式
for(i=0;i<2;i++)
printtext(temp,i);
getch();
for(i=2;i<4;i++)
printtext(temp,i);
i=0;
while(i<96&&!
kbhit())
{
sound(freq[i]); // 扬声器根据频率发声
delay(1100*dely[i]); // 声音延时
i++;
}
nosound(); // 关闭扬声器
printtext(temp,4);
getch();
closegraph(); // 关闭图形模式
}
voidprinttext(unsignedchar*temp[],inti)
{
setcolor(4); // 设置颜色
settextstyle(TRIPLEX_FONT,HORIZ_DIR,3);// 设置字符的字体,方向和大小
outtextxy(100,40+i*50,temp[i]); //在所指定的坐标出显示字符串
}
5.3.2 调用inportb()和outportb()
这个程序(例程3-38)利用3.5.2节的SOUND()和UNSOUND()改写前一实现,播放一段不同
的曲目。
/*例程3-38*/
#include
#include
voidprinttext(unsignedchar*temp[],inti);
voidSOUND(unsignedfrequency);
voidNOSOUND(void);
main()
{
inti,graphdriver,graphmode;
unsignedchar*temp[4];
intfreq[87]={196,262,262,262,330,294,262,294,330,294,262,
330,394,440,440,394,330,330,262,294,262,294,
330,294,262,230,230,196,262,440,394,330,330,
262,294,262,294,440,394,330,330,394,440,523,
394,330,330,262,294,262,294,330,294,262,230,
230,196,262,440,394,330,330,262,294,262,294,
440,394,330,330,394,440,523,394,330,330,262,
294,262,294,330,294,262,230,230,196,262};
intdely[87]={25,38,12,25,25,38,12,25,12,12,56,25,25,50,25,
38,12,12,12,38,12,25,12,12,38,12,25,25,100,25,
38,12,12,12,38,12,25,25,38,12,25,25,100,25,38,
12,12,12,38,12,25,12,12,38,12,25,25,100,25,38,
12,12,12,38,12,25,25,38,12,25,25,100,25,38,12,
12,12,38,12,25,12,12,38,12,25,25,100
}
graphdriver=DETECT;
graphmode=0;
temp[0]="Welcome!
";
temp[1]="Pleasepressanykeytostart......";
temp[2]="Enjoyyourself!
";
temp[3]="Pressanykeytoend!
";
temp[4]="Thankyou!
ByeBye......";
initgraph(&graphdriver,&graphmode,"");
cleardevice();
settextjustify(LEFT_TEXT,CENTER_TEXT);
for(i=0;i<2;i++)
printtext(temp,i);
getch();
for(i=2;i<4;i++)
printtext(temp,i);
i=0;
while(i<87&&!
kbhit())
{
SOUND(freq[i]);
delay(1100*dely[i]);
i++;
}
NOSOUND();
printtext(temp,4);
getch();
closegraph();
}
voidprinttext(unsignedchar*temp[],inti)
{
setcolor(4);
settextstyle(TRIPLEX_FONT,HORIZ_DIR,3);
outtextxy(100,40+i*50,temp[i]);
}
voidSOUND(unsignedfrequency)
{
union { /*定义由-个整数和两个字符组成的联合*/
unsigneddivisor;
unsignedcharc[2];
}tone;
tone.divisor=119328L/frequency; /* 计算该频率对应的定时器计数值 */
outportb(0x43,0xb6); /* 通知定时器采用新的计数*/
outportb(0x42,tone.c[0]);/* 计数低字节先送到定时器*/
outportb(0x42,tone.c[1]); /* 计数高字节后送到定时器*/
outportb(0x61,inportb(0x61)|3); /* 使定时器到喇叭的输出有效 */
}
voidNOSOUND(void)
{
outportb(0x61,(inportb(0x61)&0xfc));/* 使定时器到喇叭的输出无效 */
}
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 最新 语言 发声 程序
![提示](https://static.bdocx.com/images/bang_tan.gif)