C語(yǔ)言程序設(shè)計(jì)(第9章實(shí)用編程技巧)3

字號(hào):

9.3 音響技巧
    9.3.1 音樂(lè)程序設(shè)計(jì)
     我們知道,音樂(lè)是音高和音長(zhǎng)的有序組合,設(shè)計(jì)微機(jī)音樂(lè)最重要的就是如何定義音高和音長(zhǎng),以及如何讓揚(yáng)聲器發(fā)出指定的音符。下面給出音符與頻率的關(guān)系表。C語(yǔ)言提供的三個(gè)函數(shù)sound( )、nosound( )和clock( )可以很方便地解決上述的問(wèn)題。sound( )函數(shù)可以用指定頻率打開(kāi)PC機(jī)揚(yáng)聲器直到用nosound( )函數(shù)來(lái)關(guān)閉它; clock( )函數(shù)正好用來(lái)控制發(fā)聲時(shí)間,而且它不受PC機(jī)主頻高低的影響。下面這段程序可使微機(jī)發(fā)出c調(diào)1的聲音。
    表9-2 音符與頻率關(guān)系表
    音符 c d e f g a b
     1 2 3 4 5 6 7
    頻率 262 294 330 349 392 440 494
    音符 c d e f g a b
     1 2 3 4 5 6 7
    頻率 523 587 659 698 784 880 988
    音符 c d e f g a b
     1 2 3 4 5 6 7
    頻率 1047 1175 1319 1397 2568 1760 1976
    [例9-12] 音樂(lè)程序music1.c
    #include
    #include
    void pause(int);
    void sound1(int,int);
    void main(void)
    {
     int i,freq,speed=5;
     int time=4*speed;
     char *qm="iddgwwwqqgfff dddfghhhggg ddgwwwqqgfff\
     ddffhjqqqqq wpggjhgddgqq hhqwwqjjjggg\
     ddgwwwqqqgfff ddffhjqqqqqq";/*定義歌曲*/
     while (*qm++ !='\0'){
     i=1;
     switch(*qm){
     case 'k':
     time=1*speed; i=0;
     break;
     case 'i':
     time=6*speed; i=0;
     break;
     case 'o':
     time=10*speed; i=0;
     break;
     case 'p':
     pause(time); i=0;
     break;
     case 'a':
     freq=523;
     break;
     case 's':
     freq=587;
     break;
     case 'd':
     freq=659;
     break;
     case 'f':
     freq=698;
     break;
     case 'g':
     freq=784;
     break;
     case 'h':
     freq=880;
     break;
     case 'j':
     freq=988;
     break;
     case 'z':
     freq=262;
     break;
     case 'X':
     freq=294;
     break;
     case 'c':
     freq=330;
     break;
     case 'v':
     freq=349;
     break;
     case 'b':
     freq=392;
     break;
     case 'n':
     freq=440;
     break;
     case 'm':
     freq=494;
     break;
     case 'q':
     freq=1047;
     break;
     case 'w':
     freq=1175;
     break;
     case 'e':
     freq=1319;
     break;
     case 'r':
     freq=1397;
     break;
     case 't':
     freq=2568;
     break;
     case 'y':
     freq=1760;
     break;
     case 'u':
     freq=1976;
     break;
     default:
     i=0;
     break;
     }
     if(i)
     sound1(freq,time);
     }
    }
    void sound1(int freq,int time) /*freq為頻率,time為持續(xù)時(shí)間*/
    {
     union{
     long divisor;
     unsigned char c[2];
     }count;
     unsigned char ch;
     count.divisor=1193280/freq; /* 1193280 是系統(tǒng)時(shí)鐘速率*/
     outp(67,182);
     outp(66,count.c[0]);
     outp(66,count.c[1]);
     ch=inp(97);
     outp(97,ch|3);
     pause(time);
     outp(97,ch);
    }
    void pause(int time)
    {
     int t1,t2;
     union REGS in,out;
     in.h.ah=0X2c;
     int86(0X21,&in,&out); /* 取當(dāng)前時(shí)間*/
     t1=t2=100*out.h.dh+out.h.dl; /*out.h.dh 為秒值,out.h.dl 為1/100 秒值*/
     while(t2-t1     {
     int86(0X21,&in,&out);
     t2=100*out.h.dh+out.h.dl;
     if (t2     }
    }
    9.3.2 自動(dòng)識(shí)譜音樂(lè)程序
     音樂(lè)的簡(jiǎn)譜是由各種音符構(gòu)成的,將這些音符按不同的頻率、持續(xù)時(shí)間連續(xù)發(fā)出聲音,就形成了旋律。因此音樂(lè)演奏的關(guān)鍵是曲調(diào)的定義與識(shí)別及發(fā)音時(shí)間的控制。
     為了實(shí)現(xiàn)計(jì)算機(jī)自動(dòng)識(shí)譜,可定義一套曲調(diào)的編碼,其中“ 1 2 3 4 5 6 7”表示中音的1、2、3、5、6、7;高音可在中音之后加“ *”;低音在中音之后加“;”號(hào);減號(hào)“ -”表示兩拍;“.”表示一拍半;“=”表示四分之一拍;下畫(huà)線“ _”表示1 / 2拍。
     我們可用文本編輯軟件(如E D I T)按上述編碼將一首曲子的樂(lè)譜輸?shù)接?jì)算機(jī)中,得到樂(lè)譜文件供程序調(diào)用。其中樂(lè)譜文件的第一節(jié)的數(shù)字分別為:節(jié)拍基數(shù)和速度,輸入時(shí)用空格分開(kāi)。樂(lè)譜文件的第二行到最后一行為歌曲的內(nèi)容,每小節(jié)之間用“ /”分開(kāi)。
     下面根據(jù)“世上只有媽媽好”編制曲譜文件如下Ma.txt: