C語言程序設計(第9章實用編程技巧)3

字號:

9.3 音響技巧
    9.3.1 音樂程序設計
     我們知道,音樂是音高和音長的有序組合,設計微機音樂最重要的就是如何定義音高和音長,以及如何讓揚聲器發(fā)出指定的音符。下面給出音符與頻率的關系表。C語言提供的三個函數(shù)sound( )、nosound( )和clock( )可以很方便地解決上述的問題。sound( )函數(shù)可以用指定頻率打開PC機揚聲器直到用nosound( )函數(shù)來關閉它; clock( )函數(shù)正好用來控制發(fā)聲時間,而且它不受PC機主頻高低的影響。下面這段程序可使微機發(fā)出c調1的聲音。
    表9-2 音符與頻率關系表
    音符 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] 音樂程序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ù)時間*/
    {
     union{
     long divisor;
     unsigned char c[2];
     }count;
     unsigned char ch;
     count.divisor=1193280/freq; /* 1193280 是系統(tǒng)時鐘速率*/
     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); /* 取當前時間*/
     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 自動識譜音樂程序
     音樂的簡譜是由各種音符構成的,將這些音符按不同的頻率、持續(xù)時間連續(xù)發(fā)出聲音,就形成了旋律。因此音樂演奏的關鍵是曲調的定義與識別及發(fā)音時間的控制。
     為了實現(xiàn)計算機自動識譜,可定義一套曲調的編碼,其中“ 1 2 3 4 5 6 7”表示中音的1、2、3、5、6、7;高音可在中音之后加“ *”;低音在中音之后加“;”號;減號“ -”表示兩拍;“.”表示一拍半;“=”表示四分之一拍;下畫線“ _”表示1 / 2拍。
     我們可用文本編輯軟件(如E D I T)按上述編碼將一首曲子的樂譜輸?shù)接嬎銠C中,得到樂譜文件供程序調用。其中樂譜文件的第一節(jié)的數(shù)字分別為:節(jié)拍基數(shù)和速度,輸入時用空格分開。樂譜文件的第二行到最后一行為歌曲的內容,每小節(jié)之間用“ /”分開。
     下面根據(jù)“世上只有媽媽好”編制曲譜文件如下Ma.txt: