很早以前就想写个这样的东西,不过自己是音痴,不会读乐谱.
上次在看雪上看到 玩命大牛写的用BEEP做的《送别》之后,摘抄了曲子,自己实现了直接IO版本.

有几个小细节需要解释: 
驱动喇叭的端口:0x61,0x40-0x43. 

0x40-0x42是3个计数器,0x40控制系统时钟,0x41控制DRAM刷新的,0x42就是留给一般应用,比如扬声器,我们要用到的就是0x42. 

0x43是这3个计数器的控制端口,下面详细解释. 

这些端口都是8位操作的,所以每次读写只能操作8位数据. 

我在程序中给0x43 OUT 的是0xB6,即10110100. 
第0位是0,表示写入的是二进制数, 
第1-3位代表计数器的运行方式,010代表以方式2运行,即分频器方式. 
第4-5位代表给0x40-0x42端口读写数据的方式,11代表先读低8位,再读高8位. 
第6-7位代表选择的计数器,10代表选择选择计数器2,即0x42端口. 

再来解释0x61端口. 
计数器2的时钟信号一个1193180Hz的输入,计数器2的另外一个输入是0x61端口的第0位,当第0位为1时,计数器2启动. 
另外,计数器2的输出端和0x61端口的第1位经过与门之后输出到喇叭,以此来驱动喇叭. 

所以要让喇叭启动,就把0x61端口的低两位置1就可以了,要停止就置0. 

详细的看代码.

解释完了,希望不是废话.

下面看代码. 

代码:
#define ONE_MyBeep 600 
#define HALF_MyBeep 300 


#define NOTE_1 440 
#define NOTE_2 495 
#define NOTE_3 550 
#define NOTE_4 587 
#define NOTE_5 660 
#define NOTE_6 733 
#define NOTE_7 825 


UCHAR In_8(PUCHAR Port) 
{ 
UCHAR Value; 
__asm 
{ 
mov edx,Port 
in al,dx 
mov Value,al 
nop 
nop 
} 
return Value; 
} 


void Out_8(PUCHAR Port,UCHAR Value) 
{ 
__asm 
{ 
mov edx,Port 
mov al,Value 
out dx,al 
nop 
nop 
} 
} 

void MyBeep(USHORT freq,ULONG duration) 
{ 
LARGE_INTEGER timeout; 

UCHAR stop; 

USHORT timer=1193180/freq; 

UCHAR start; 
start=In_8((PUCHAR)0x61); 
start=start|3; 


timeout=RtlConvertLongToLargeInteger(-10000*duration); 


/*0x61端口低两位置1,启动喇叭*/ 
Out_8((PUCHAR)0x61,start); 

/*计数器控制端口0x43,置位为10110100*/ 
Out_8((PUCHAR)0x43,0xB4); 

/*先写低八位*/ 
Out_8((PUCHAR)0x42,timer&0xF); 

/*再写高八位*/ 
Out_8((PUCHAR)0x42,(timer>>8)&0xF); 

/*喇叭持续时间*/ 
KeDelayExecutionThread(KernelMode,FALSE,&timeout); 


/*0x61端口低两位置0,停止喇叭*/ 
stop=In_8((PUCHAR)0x61); 
stop=stop&0xFC; 
Out_8((PUCHAR)0x61,stop); 

} 



void PlayMusic(void) 
{ 
MyBeep(NOTE_5, ONE_MyBeep); 
MyBeep(NOTE_3, HALF_MyBeep); 
MyBeep(NOTE_5, HALF_MyBeep); 
MyBeep(NOTE_1*2, ONE_MyBeep*2); 

MyBeep(NOTE_6, ONE_MyBeep); 
MyBeep(NOTE_1*2, ONE_MyBeep); 
MyBeep(NOTE_5, ONE_MyBeep*2); 

MyBeep(NOTE_5, ONE_MyBeep); 
MyBeep(NOTE_1, HALF_MyBeep); 
MyBeep(NOTE_2, HALF_MyBeep); 
MyBeep(NOTE_3, ONE_MyBeep); 
MyBeep(NOTE_2, HALF_MyBeep); 
MyBeep(NOTE_1, HALF_MyBeep); 
MyBeep(NOTE_2, ONE_MyBeep*4); 

MyBeep(NOTE_5, ONE_MyBeep); 
MyBeep(NOTE_3, HALF_MyBeep); 
MyBeep(NOTE_5, HALF_MyBeep); 
MyBeep(NOTE_1*2, HALF_MyBeep*3); 
MyBeep(NOTE_7, HALF_MyBeep); 
MyBeep(NOTE_6, ONE_MyBeep); 
MyBeep(NOTE_1*2, ONE_MyBeep); 
MyBeep(NOTE_5, ONE_MyBeep*2); 

MyBeep(NOTE_5, ONE_MyBeep); 
MyBeep(NOTE_2, HALF_MyBeep); 
MyBeep(NOTE_3, HALF_MyBeep); 
MyBeep(NOTE_4, HALF_MyBeep*3); 
MyBeep(NOTE_7/2, HALF_MyBeep); 
MyBeep(NOTE_1, ONE_MyBeep*4); 

MyBeep(NOTE_6, ONE_MyBeep); 
MyBeep(NOTE_1*2, ONE_MyBeep); 
MyBeep(NOTE_1*2, ONE_MyBeep*2); 

MyBeep(NOTE_7, ONE_MyBeep); 
MyBeep(NOTE_6, HALF_MyBeep); 
MyBeep(NOTE_7, HALF_MyBeep); 
MyBeep(NOTE_1*2, ONE_MyBeep*2); 

MyBeep(NOTE_6, HALF_MyBeep); 
MyBeep(NOTE_7, HALF_MyBeep); 
MyBeep(NOTE_1*2, HALF_MyBeep); 
MyBeep(NOTE_6, HALF_MyBeep); 
MyBeep(NOTE_6, HALF_MyBeep); 
MyBeep(NOTE_5, HALF_MyBeep); 
MyBeep(NOTE_3, HALF_MyBeep); 
MyBeep(NOTE_1, HALF_MyBeep); 
MyBeep(NOTE_2, ONE_MyBeep*4); 

MyBeep(NOTE_5, ONE_MyBeep); 
MyBeep(NOTE_3, HALF_MyBeep); 
MyBeep(NOTE_5, HALF_MyBeep); 
MyBeep(NOTE_1*2, HALF_MyBeep*3); 
MyBeep(NOTE_7, HALF_MyBeep); 
MyBeep(NOTE_6, ONE_MyBeep); 
MyBeep(NOTE_1*2, ONE_MyBeep); 
MyBeep(NOTE_5, ONE_MyBeep*2); 

MyBeep(NOTE_5, ONE_MyBeep); 
MyBeep(NOTE_2, HALF_MyBeep); 
MyBeep(NOTE_3, HALF_MyBeep); 
MyBeep(NOTE_4, HALF_MyBeep*3); 
MyBeep(NOTE_7/2, HALF_MyBeep); 
MyBeep(NOTE_1, ONE_MyBeep*3); 

} 
上传的附件 PlayMusic.rar