还剩12页未读,继续阅读
本资源只提供10页预览,全部文档请下载后查看!喜欢就下载吧,查找使用更方便
文本内容:
C语言高级程序设计讲座3C语言程序设计2009-07-2708:48阅读156评论0字号大中小小经过上面两节课的学习,我们应该对C语言的图形设计有一定的了解,这节课我们主要讲一下C语言的发音,让你的程序声图并茂学习目标•学习用C语言发声•了解声音功能函数•了解乐谱文件的制作•能够结合图像与声音,让你的程序声图并茂打破沉寂首先我们来看一个源代码#defineFALSE0#defineTRUE1#includedos.h__in{intsnd;/*whichsoundtoprodu__*/intcnt;/*numberoftimestorepeatsound*/intnote;/*Currentnotewhensweepingfrequencies*/whileTRUE{/*__leSureanyprevioussounds__eturnedoff.*/nosound;/*Asktheuserforwhichtypeofsounf*/printf1-siren;2-overload;3-whoop;4-phaser;0-exit;/*readtheanswer*/scanf%dsnd;/*iftheanswerittoexitdoso.*/ifsnd==0break;/*Askhow__nytimestorepastthesound.*/printfNungeroftimes:;/*gettheanswer*/scanf%dcnt;/*repeatthesoundthenumberoftimespecifed*/whilecnt--{/*swichontypeofsoundtoprodu__*/switchsnd{case1:/*doasiren:sweepup*/fornote=1000;note150;note-=10{soundnote;delay20;}/*Sweepdown*/for;note1000;note+=10{soundnote;delay20;}break;case2:/*doanoverload.sweepup*/fornote=4000;note10;note-=10{soundnote;delay70;}break;case3:/*doawhoop:Sweepup*/fornote=1000;note10;note-=10{soundnote;delay200;}break;case4:/*doaphaser:sweepdown*/fornote=60;note2000;note+=10{soundnote;delay100;}break;default:/*unknownaskagain*/printfInvalidentry;tryagain\n;break;}}}}请大家打开TC运行该代码,程序重复的询问用户要产生哪一种声音C语言调用两个库函数使PC发出声音sound打开声音;nosound关闭声音他们包含在dos.h中,格式如下voidsoundunsignedintfrequency;voidnosoundvoid;其中frequency为频率,单位Hz为了使声音持续一段时间,我们还常用delay函数,格式如下voiddelayunsignedintmilliseconde;其中milliseconde表示所需延时的时间下面这个例子将不断发出各种频率的声音#includedos.h#includestdio.h#includestdlib.h#includetime.h__in{intij;randomize;while!bioskey1{i=rand*5000;soundi;delay10;}nosound;}前台音乐设计首先我们来看下面这个例子,演奏的是《好人一生平安》#includetime.h#includedos.h#defineN164#defineN232#defineN416#defineN88#defineN164#defineEND0enumNOTES{C10=131D10=147E10=165F10=175G10=196A10=220B10=247C0=262D0=296E0=330F0=349G0=392A0=440B0=494C1=525D1=587E1=659F1=698G1=784A1=880B1=988C2=1047D2=1175E2=1319F2=1397G2=1568A2=1760B2=1796}song[]={D0N4E0N8D0N8C0N4A10N4G10N8E10N8G10N8A10N8C0N2A10N4A10N8C0N8G10N8A0N8E0N8G0N8D0N2E0N4D0N8E0N8G0N4E0N4G10N8E10N8G10N8A10N8C0N2A10N4A10N8C0N8A10N8A10N8D10N8E10N8G10N2D0N4D0N4G0N4A0N8G0N8F0N2G0N2A0N4G0N8E0N8D0N8E0N8C0N8A10N8D0N2E0N4G0N8E0N8G0N4E0N4G10N8E10N8G10N8A10N8C0N4A10N4A10N8C0N8D0N8A10N8C0N8E0N8D0N1ENDEND};__in{intnote=0fredurcontrol;clock_tgoal;whilesong[note]!=0{fre=song[note];dur=song[note+1];ifkbhitbreak;iffre{outportb0x430xb6;fre=unsigned1193180L/fre;outportb0x42charfre;outportb0x42charfre8;control=inportb0x61;outportb0x61control|0x3;}goal=clock_tdur+clock;whilegoalclock;iffreoutportb0x61control;goal=clock_t0;note=note+2;}}音乐是时间的艺术,即把各种音符按不同的时值演奏出来,就可以构成曲调因此,音乐程序设计中的两个重要因素是如何用“曲调定义语言”来表示音符即音高;如何控制音符的持续时间即音长解决了这两个问题之后,剩下的就是如何用c语言控制计算机的扬声器发声下面我们详细的讲解一下1音符及音长的定义音调由音符构成,音调的高低由音符频率决定,频率越高,音调也越高音乐中使用的频率一般为131~1976HZ,它包括了__C调及其前后的4个8度的音程用c语言中的枚举类型常量可定义上述表中的各音符的频率如果音乐中有比表中的音符更高的音调,则可根据表上的有关值推出,如高8度的CD和E的频率分别为2091,2350和2638,还需作适当的调整EnumNOTES{C10=131DlO=147ElO=165FlO=175GlO=196A10=220B10=247.CO=262DO=294EO=330FO=349GO=392AO=440BO=494,C1=523Dl=587EI=659Fl=698G1=784A1=880B1=988,C2=1047D2=1175E2=1319F2=1397G2=1568A2=1760B2=1976音长即一个音符的持续题意在乐曲中,音长用全音符、半音符、4分音符……来表示,通常以4分音符一拍,等等音长可用下面定义#defineN132#defineN216#defineN48#defineN84#defineN162#defineEND0如果感觉计算机所演奏的乐曲速度过快可以适当调整上面的值2用C语言定义音乐NOTES类型中各音调对应的简谱如下上面的乐谱共有10个音符,其音高和音长如下3如何控制扬声器如何控制扬声器发生,则可用TurboC中的库函数中outportbintportcharbyte,函数的原型在”dos.h”文件中,port为端口地址,byte为传送给端口的字节扬声器的端也址为0x42,下面的程序中主要是发声的频率另外,还需要使发声延迟,就要用到”clock_t”,类型变量goal和clock库函数,变量和程序的原型在”time.h”文件中,使扬声器发声的步骤为
①初始化端口0x42;
②向端口0x42传送声频率fre;
③延迟当goalclock时,做循环后台音乐设计后台音乐设计主要是程序的背景声音,看下面的例子#includestdio.h#includedos.h#includegraphics.h#includefcntl.h#includetime.h#defineN164#defineN232#defineN416#defineN88#defineN164#defineEND0voidinterrupt*handler;voidinterruptmusic;inthandlecontrol;enumNOTES{C10=131D10=147E10=165F10=175G10=196A10=220B10=247C0=262D0=296E0=330F0=349G0=392A0=440B0=494C1=523D1=587E1=659F1=698G1=784A1=880B1=988C2=1047D2=1175E2=1319F2=1397G2=1568A2=1760B2=1796}song[]={E1N4E1N8E1N8F1N4G1N4F1N4F1N4E1N4D1N4C1N4C1N4D1N4E1N4E1N4D1N4D1N4E1N4E1N8E1N8F1N4G1N4G1N4F1N4E1N4D1N4C1N4C1N4D1N4E1N4D1N4D1N4C1N4D1N4D1N8D1N8E1N4C1N4D1N4E1N8F1N8E1N4C1N4D1N4E1N8F1N8E1N4C1N4C1N4D1N4G0N4E1N4E1N4E1N8F1N4G1N4G1N4F1N4E1N4D1N4C1N4C1N4D1N4E1N4E1N4D1N4C1N4D1N4ENDEND};__in{intgdriver=VGAgmode=1i;initgraphgdrivergmode;handler=getvect0x1c;setvect0x1cmusic;cleardevi__;setbkcolorBLUE;setcolorYELLOW;setfillstyleSOLID_FILLRED;sector200150501207050;bar3d400150500200105;setactivepage1;sector200150501707050;bar3d400200500250105;fori=0;i100;i++{whilekbhitgotoend;setvisualpage1;delay100-i*10;setvisualpage0;delay100-i*10;}end:;outportb0x61control0xfe;setvect0x1chandler;cleardevi__;closegraph;}voidinterruptmusic{staticintflag=0note=0fredur=8;flag++;fre=song[note];dur=song[note+1];if/*flagintdur*2/5*/fre{flag=0;outportb0x430xb6;fre=unsigned1193180L/fre;outportb0x42charfre;outportb0x42charfre8;control=inportb0x61;outportb0x61control|0x3;note=note+2;ifnote=134note=0;}handler;}乐谱文件的制作我们在这里使用的乐谱文件格式如下最高音的前面加”*”;高音,在每个音的前面加”h”;中音,在每个音的前面加”m”;低音,在每个音的前面加”L”“*”、“h”、“m”、“L”与其控制的音符构成音高,决定发声频率音高的后面是音长,可用整数或小数输入,以控制延时,但中间必须用空格分开乐谱文件的最前端是一个整数,表示音长基数,一般为
300、
600、
900、1200乐谱文件的最末端是乐谱文件结束符”##”,以表示乐谱文件结束下面是电影《城南旧事》插曲《送别》的一段乐谱文件为600m51m
30.5m
50.5hl2m61hl
0.5m
60.5m52m5Iml
0.5m
20.5m31m
20.5ml
0.5m23##每个音的音长=音长基数*节拍数,其中,音长基数是乐谱文件的第一个字符,如上面乐谱文件为600,每个音的音频可用一摸拟频率值输入下面是程序源代码、编译、连接成可执行文件music.exe,用法为music乐谱文件#includestdlib.h#includestdio.h#includedos.h#includeconio.hvoid__inintar__char*argv[]{FILE*fp;intrate;charsound_high
[3];floatsound_long;registerinti=0j;intsign=0;floatstr
[100]
[2];ifar__!=2/*命令行参数个数不正确*/{printfPararnetersErrors!\n;exit1;}iffp=fopenargv
[1]r==NULL/* 文件打开失败*/{printfopenfilemusicdocErrors!\n;exit1;}fscanffp%drate;/*读取音长基数的值 */while!feoffp!sign/*文件没有结束并且数据还是乐谱*/{fscanffp%s%fsound_highsound_long;/*得到音频、音长的数值*/str
[1]=rate*sound_long;/* 音乐=音长基数*节拍数*/switchsound_high
[0]{case*:/*最高音*/switchsound_high
[1]{/*确定发音的频率*/case1:str[i++]
[0]=
1046.5;break;case2:str[i++]
[0]=
1174.7;break;case3:str[i++]
[0]=
1318.5;break;case4:str[i++]
[0]=
1396.9;brcak:case5:str[i++]
[0]=1568;break;case6:str[i++]
[0]=1760;break;case7:str[i++]
[0]=
1975.5;break;default:printf\nErrorsinmusic.doc\n;exit1;break;}break;caseh:/*高音*/switchsound_high
[1]{case1:str[i++]
[0]=
523.3;break;case2:str[i++]
[0]=
587.3;break;case3:str[i++]
[0]=
659.3;break;case4:str[i++]
[0]=
698.5;break;case5:str[i++]
[0]=
784.0;break;case6:str[i++]
[0]=880;break;case7:str[i++]
[0]=
987.8;break;default:printf\nErrorsinmusic.doc\n;exit1;break;}break;casem:/*中音*/switchsound_high
[1]{case1:str[i++]
[0]=262;break;case2:str[i++]
[0]=296;break;case3:str[i++]
[0]=
329.6;break;case4:str[i++]
[0]=
349.2;break;case5:str[i++]
[0]=392;break;case6:str[i++]
[0]=440;break;case7:str[i++]
[0]=
493.9;break;default:printf\nErrorsinmusic.doc\n;exit1;break;}break;casel:/*低音*/switchsound_high
[1]{case1:str[i++]
[0]=131;break;case2:str[i++]
[0]=147;break;case3:str[i++]
[0]=165;break;case4:str[i++]
[0]=176;break;case5:str[i++]
[0]=196;break;case6:str[i++]
[0]=220;break;case7:str[i++]
[0]=247;break;default:printf\nErrorsinmusic.doc\n;exit1;break;}break;case#:ifsound_high
[1]==#sign=1;break;default:printf\nErrorsinmusic.doc\n;exit1;}}forj=0;ji;j++{soundstr[j]
[0];/*按频率值发出歌曲的音调*/delaystr[j]
[1];}nosound;/*关闭扬声器*/}声图并茂我们来看下面这个程序的源代码,实现的是一个表盘的走动,并且发出响声,整点还有报时功能#include__th.h#includedos.h#includegraphics.h#define__NTERX320/*表盘中心位置*/#define__NTERY175#defineCLICK100/*喀嗒声频率*/#defineCLICKDELAY30/*喀嗒声延时*/#defineHEBEEP_____/*高声频率*/#defineLOWBEEP500/*低声频率*/#defineBEEPDELAY200/*报时声延时*//*表盘刻度形状*/intMrk_1
[8]={-5-1605-1605-130-5-130};intMrk_2
[8]={-5-1605-1602-130-2-130};/*时针形状*/intHourHand
[8]={-3-1003-120410-410};/*分针形状*/intMiHand
[8]={-3-1203-120410-410};/*秒针形状*/intSecHand
[8]={-2-1502-150310-310};/*发出喀嗒声*/voidClick{soundCLICK;delayCLICKDELAY;nosound;}/*高声报时*/voidHi___eep{soundHEBEEP;delayBEEPDELAY;nosound;}/*低声报时*/voidLowBeep{soundLOWBEEP;}/*按任意角度画多边形*/voidDrawPolyint*dataintangleintcolor{intusedata
[8];floatsinangcosang;inti;sinang=sinfloatangle/180*
3.14;cosang=cosfloatangle/180*
3.14;fori=0;i8;i+=2{usedata=__NTERX+cosang*data-sinang*data[i+1]+.5;usedata[i+1]=__NTERY+sinang*data+cosang*data[i+1]+.5;}setfillstyleSOLID_FILLcolor;fillpoly4usedata;}/*画表盘*/voidDrawClockstructtime*cutime{intang;floathourrateminratesecrate;setbkcolorBLUE;cleardevi__;setcolorWHITE;/*画刻度*/forang=0;ang360;ang+=90{DrawPolyMrk_1angWHITE;DrawPolyMrk_2ang+30WHITE;DrawPolyMrk_2ang+60WHITE;}secrate=floatcutime-ti_sec/60;minrate=floatcutime-ti_min+secrate/60;hourrate=floatcutime-ti_hour/12+minrate/12;ang=hourrate*360;DrawPolyHourHandangYELLOW;/*画时针*/ang=minrate*360;DrawPolyMiHandangGREEN;/*画分针*/ang=secrate*360;DrawPolySecHandangRED;/*画秒针*/}__in{intgdriver=EGAgmode=EGAHI;intcurpage;structtimecurtimenewtime;initgraphgdrivergmodec:\\tc;setbkcolorBLUE;cleardevi__;gettimecurtime;curpage=0;DrawClockcurtime;while1{ifkbhitbreak;/*按任意键退出*/gettimenewtime;/*检测系统时间*/ifnewtime.ti_sec!=curtime.ti_sec/*每1秒更新一次时间*/{ifcurpage==0curpage=1;elsecurpage=0;curtime=newtime;/*设置绘图页*/setactivepagecurpage;/*在图页上画表盘*/DrawClockcurtime;/*设置绘图页为当前可见页*/setvisualpagecurpage;/*0分0秒高声报时*/ifnewtime.ti_min==0newtime.ti_sec==0Hi___eep;/*59分55至秒时低声报时*/elseifnewtime.ti_min==59newtime.ti_sec=59LowBeep;/*其他时间只发出喀嗒声*/elseClick;}}closegraph;}。