📄 sound.c
字号:
/*
sound.c
扬声器播放音乐函数实现
最后修改: 2007-06-19
*/
#include "sound.h"
#include <stdio.h>
#include <dos.h>
char g_byPause=0;
char g_nIsPlaying=0;
double g_dMinLength;
double g_dPlayed, g_dLast;
char *g_sNote;
FILE *g_pFile;
char g_szMusicPath[13]="music\\00.mus";
char g_nMusicNum=0;
void interrupt far (*OldTimer)();
unsigned int freq[5][12]= /* 暂时就用这 5 个八度的音域 */
{
{ 65, 69, 73, 78, 82, 87, 93, 98, 104, 110, 117, 123}, /* C0 - #B0 大字组 */
{ 131, 139, 147, 156, 165, 175, 185, 196, 208, 220, 233, 247}, /* c0 - #b0 小字组 */
{ 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494}, /* c1 - #b1 小字一组 */
{ 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988}, /* c2 - #b2 小字二组 */
{1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1976} /* c3 - #b3 小字三组 */
};
char IsPlaying() /* 是否正在播放 */
{
return g_nIsPlaying;
}
void PausePlay() /* 暂停播放 */
{
g_byPause=!g_byPause;
}
unsigned int GetFreq(char note[4])
{
/*
音符格式说明
第一个字符: #, b, n 之中的一个,分别表示升、降、还原
第二个字符: 大写或小写的 C, D, E, F, G, A, B, 表示音名
第三个字符: 0, 1, 2, 3
组合起来表示一个音符, 例如:
#C0 表示大字组的 #C 音, 对应上面的频率为 69Hz
na1 表示小字一组的 A 音, 频率为 440Hz
bg2 表示小字二组的 bG 音, 频率为 740Hz
*/
char flag=note[0], name=note[1], group=note[2]-'0'+1;
if(name>='A'&&name<='G')
{
name+=32;
group=-group-1;
}
switch(name)
{
case 'c': name=0; break;
case 'd': name=2; break;
case 'e': name=4; break;
case 'f': name=5; break;
case 'g': name=7; break;
case 'a': name=9; break;
case 'b': name=11; break;
default :return 0; /* 其它所有均理解为休止符 */
}
switch(flag)
{
case '#':
name++;
if(name>=12)
{
name-=12;
group++;
}
break;
case 'b':
name--;
if(name<0)
{
name+=12;
group--;
}
}
if(group>=-1&&group<=3)
{
return freq[group][name];
}
}
void CloseSound() /* 关闭声音 */
{
setvect(0x1c, OldTimer);
nosound();
fclose(g_pFile);
}
void far interrupt Play() /* 中断服务程序 */
{
int freq;
(*OldTimer)();
if(g_byPause!=0)
{
if(g_dPlayed>=g_dLast)
{
fscanf(g_pFile, "%s", g_sNote);
if(g_sNote[0]=='E'&&g_sNote[1]=='N'&&g_sNote[2]=='D'&&g_sNote[3]=='\0') /* 如果是结束符 */
{
g_nIsPlaying=0;
g_nMusicNum++;
CloseSound();
return;
}
freq=GetFreq(g_sNote);
fscanf(g_pFile, "%lf", &g_dLast);
g_dLast*=g_dMinLength;
g_dPlayed=0;
if(freq==0) nosound();
else sound(freq);
}
g_dPlayed+=54.945;
}
else
{
nosound();
}
}
/*
文件格式说明
第一个数, 每秒钟的拍数
接下去一个音符、一个拍数(可以为小数), 空格分开
RST 表示休止符, 也作为一个音符记号
文件最后要有大写 END 来结束
相邻两音同音高不会自己停一下, 要手动加休止符
具体见 music 下的文件
*/
char PlayBack(char *szFileName) /* 后台播放 */
{
g_pFile=fopen(szFileName, "r");
if(g_pFile!=NULL)
{
fscanf(g_pFile, "%lf", &g_dMinLength);
g_dMinLength=60000/g_dMinLength;
g_dPlayed=0;
g_dLast=0;
g_nIsPlaying=1;
OldTimer=getvect(0x1c);
setvect(0x1c, Play);
return 1;
}
return 0;
}
void PlayMusic() /* 寻找文件并播放 */
{
if(g_nMusicNum>99) g_nMusicNum=0;
g_szMusicPath[7]='0'+g_nMusicNum%10;
g_szMusicPath[6]='0'+g_nMusicNum/10;
if(!PlayBack(g_szMusicPath)) g_nMusicNum++;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -