今年4月24日,是我國發射第一顆人造地球衛星——“東方紅1號”,50週年的紀念日。讀了許多紀念文章,耳邊彷彿就響起“東方紅”的樂曲。忽然想起多年前寫過一個演奏樂曲的小程序,它讀取經過簡單翻譯的簡譜,然後利用PC機的揚聲器演奏出樂曲來。演奏的第一個樂曲就是“東方紅”。特地將程序放上來,紀念這個偉大的日子。
當時的想法有點奇怪,並不是直接讀譜演奏,而是讀譜以後生成另一個源程序,這個派生的源程序將音符和節拍,計算成音頻和延時後直接寫入代碼中,然後才演奏。當時也許是爲了分發最後生成的奏樂執行程序方便吧。現在原文照錄。
讀譜生成代碼的程序:genmusic.cpp.
#include<stdio.h>
#include<string>
#include<windows.h>
using namespace std;
class Piccolo {
private:
int T; // basic duration
DWORD Hz[8];
FILE *sp; // file to read
FILE *tp; // file to write
void gennote(int hz,int i,int t)
/* 讀簡譜生成奏樂文件。 hz代表音符,i代表音調:0爲低音,1爲正常,2爲高音。t代表節拍:1=0.25拍,2=0.5拍,3=0.75拍,4=1拍,以此類推。即t=節拍數x4 */
{
DWORD dhz,dur;
dhz=Hz[hz];
dur=60000/T/4*t; // 調整節拍的時長。
if (i==0) dhz=dhz/2; //低音
if (i==2) dhz=dhz*2; //高音
fprintf(tp," song.push_back(%d);\n",dhz);
fprintf(tp," song.push_back(%d);\n",dur);
printf(" Beep(%d,%d);\n",dhz,dur); // print to screen
}
public:
Piccolo(void)
{
/* 基本音符的頻率 */
Hz[1]=1300;
Hz[2]=1463;
Hz[3]=1625;
Hz[4]=1733;
Hz[5]=1950;
Hz[6]=2167;
Hz[7]=2438;
}
void genmusic(string sn)
{
DWORD hz,t,x;
string sfn,tfn;
sfn=sn+".txt"; // 讀入的簡譜文件,每個音爲一行:第一個爲音符,第二爲音調,第三爲節拍。-1代表結束。
tfn=sn+".cpp"; // 產生的奏樂程序。根據簡譜計算出頻率和延時,產生Beep(hz,duration)函數
if (sp=fopen(sfn.c_str(),"r")) {
if (tp=fopen(tfn.c_str(),"w")) {
fscanf(sp,"%d",&T); // 首先讀入的是節拍的時長。一般100毫秒爲一個四分之一拍比較合適
cout<<T<<endl; //printf("%d\n",T);
fprintf(tp,"#include<stdio.h>\n"); // 寫入奏樂程序的包含文件
fprintf(tp,"#include<vector>\n");
fprintf(tp,"#include<windows.h>\n");
fprintf(tp,"using namespace std;\n");
fprintf(tp,"int main(void)\n{\n");
fprintf(tp," vector<DWORD> song;\n");
while(!feof(sp))
{
fscanf(sp,"%d %d %d",&hz,&x,&t);
if(hz!=-1) {
cout<<hz<<' '<<x<<' '<<t<<endl; //printf("%d%c%d%c%d\n",hz,' ',x,' ',t);
gennote(hz,x,t); // 將每個音的音符、音調、節拍寫入奏樂程序
}
else break;
}
fprintf(tp," for(size_t sz=song.size(), i=0; i!=sz; i+=2) {\n for(int j=0;j<song[i+1];j+=100) printf(\"+\");\n Beep(song[i],song[i+1]);\n printf(\"\\n\");\n }\n");
fprintf(tp," return 0;\n}");
fclose(sp);
sp=NULL;
fclose(tp);
tp=NULL;
}
else cout<<"Error:file "+tfn+" cannot be created."<<endl; // 在當前目錄沒有建立文件的權限
}
else cout<<"Error: file "+sfn+" is not found."<<endl; // 簡譜文件不存在
}
};
int main(void)
{
Piccolo pic;
pic.genmusic("dongfanghong");
return 0;
}
簡譜文件:dongfanghong.txt。第一行是節拍的時長。一般100毫秒爲一個四分之一拍比較合適。跟着的就是簡譜。每個音爲一行:第一個爲音符(1、2、3、4、5、6、7),第二爲音調(0爲低音,1爲中音,2爲高音),第三爲節拍(1=0.25拍,2=0.5拍,3=0.75拍,4=1拍,以此類推)。-1代表結束。
100
5 1 4
2 1 4
1 1 4
7 0 2
6 0 2
5 0 4
5 1 4
2 1 4
3 1 2
2 1 2
1 1 4
1 1 2
6 0 2
2 1 2
3 1 2
2 1 2
1 1 2
2 1 2
1 1 2
7 0 2
6 0 2
5 0 12
0 1 4
5 1 4
5 1 2
6 1 2
2 1 8
1 1 4
1 1 2
6 0 2
2 1 8
5 1 4
5 1 4
6 1 2
1 1 2
6 1 2
5 1 2
1 1 4
1 1 2
6 1 2
2 1 8
5 1 4
2 1 4
1 1 4
7 0 2
6 0 2
5 0 4
5 1 4
2 1 4
3 1 2
2 1 2
1 1 4
1 1 2
6 0 2
2 1 2
3 1 2
2 1 2
1 1 2
2 1 2
1 1 2
7 0 2
6 0 2
5 0 12
0 1 4
-1 -1 -1
編譯並運行這個genmusic.cpp,生成奏樂程序源文件:dongfanghong.cpp。
#include<stdio.h>
#include<vector>
#include<windows.h>
using namespace std;
int main(void)
{
vector<DWORD> song;
song.push_back(1950);
song.push_back(600);
song.push_back(1463);
song.push_back(600);
song.push_back(1300);
song.push_back(600);
song.push_back(1219);
song.push_back(300);
song.push_back(1083);
song.push_back(300);
song.push_back(975);
song.push_back(600);
song.push_back(1950);
song.push_back(600);
song.push_back(1463);
song.push_back(600);
song.push_back(1625);
song.push_back(300);
song.push_back(1463);
song.push_back(300);
song.push_back(1300);
song.push_back(600);
song.push_back(1300);
song.push_back(300);
song.push_back(1083);
song.push_back(300);
song.push_back(1463);
song.push_back(300);
song.push_back(1625);
song.push_back(300);
song.push_back(1463);
song.push_back(300);
song.push_back(1300);
song.push_back(300);
song.push_back(1463);
song.push_back(300);
song.push_back(1300);
song.push_back(300);
song.push_back(1219);
song.push_back(300);
song.push_back(1083);
song.push_back(300);
song.push_back(975);
song.push_back(1800);
song.push_back(4200400);
song.push_back(600);
song.push_back(1950);
song.push_back(600);
song.push_back(1950);
song.push_back(300);
song.push_back(2167);
song.push_back(300);
song.push_back(1463);
song.push_back(1200);
song.push_back(1300);
song.push_back(600);
song.push_back(1300);
song.push_back(300);
song.push_back(1083);
song.push_back(300);
song.push_back(1463);
song.push_back(1200);
song.push_back(1950);
song.push_back(600);
song.push_back(1950);
song.push_back(600);
song.push_back(2167);
song.push_back(300);
song.push_back(1300);
song.push_back(300);
song.push_back(2167);
song.push_back(300);
song.push_back(1950);
song.push_back(300);
song.push_back(1300);
song.push_back(600);
song.push_back(1300);
song.push_back(300);
song.push_back(2167);
song.push_back(300);
song.push_back(1463);
song.push_back(1200);
song.push_back(1950);
song.push_back(600);
song.push_back(1463);
song.push_back(600);
song.push_back(1300);
song.push_back(600);
song.push_back(1219);
song.push_back(300);
song.push_back(1083);
song.push_back(300);
song.push_back(975);
song.push_back(600);
song.push_back(1950);
song.push_back(600);
song.push_back(1463);
song.push_back(600);
song.push_back(1625);
song.push_back(300);
song.push_back(1463);
song.push_back(300);
song.push_back(1300);
song.push_back(600);
song.push_back(1300);
song.push_back(300);
song.push_back(1083);
song.push_back(300);
song.push_back(1463);
song.push_back(300);
song.push_back(1625);
song.push_back(300);
song.push_back(1463);
song.push_back(300);
song.push_back(1300);
song.push_back(300);
song.push_back(1463);
song.push_back(300);
song.push_back(1300);
song.push_back(300);
song.push_back(1219);
song.push_back(300);
song.push_back(1083);
song.push_back(300);
song.push_back(975);
song.push_back(1800);
song.push_back(4200400);
song.push_back(600);
for(size_t sz=song.size(), i=0; i!=sz; i+=2) {
for(int j=0;j<song[i+1];j+=100) printf("+");
Beep(song[i],song[i+1]);
printf("\n");
}
return 0;
}
編譯,運行這個dongfanghong.cpp程序,“東方紅”的樂曲就奏響了!