⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sound.c

📁 坦克大战,实现基本的游戏功能
💻 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 + -