不知道怎么往这个简易钢琴程序里加音频文件,而且我的电脑没法运行这个软件,求解答一下

不知道怎么往这个简易钢琴程序里加音频文件,而且我的电脑没法运行这个软件,求解答一下

问题描述:


#include<thread>       
#include<iostream>
#include<string.h>
#include<windows.h>
#include<conio.h>
#include<mmsystem.h>
#include<stdlib.h>

using namespace std;

#pragma comment(lib,"winmm.lib") //[1]

#define MAXLEN 127
#define XSTART 16
#define YSTART 5
#define LENOFPAGE 146
#define DEPTHOFPAGE 20
short piano_type=1;    //2表示亮音钢琴,1是原声钢琴

typedef union{
    int i;
    char c[10];
}CwithI;

typedef struct{
    char name[MAXLEN];
    CwithI qusu;
    char ver[20];
}HEAD;

void play_sound(char keyboard_key);//播放音频
void play_song(FILE *puzi,short *ystart,HEAD mus_info,short *flag);//播放音乐
void decoding_func(char keyboard_key,char *sound_name,short piano_type);//解码
void gotoxy(int x,int y);//移动光标至指定位置
void print_kuang();//打印框框
void print_pkeys();//打印手动模式下的静态钢琴键盘
void cls_kuang(short,short);//清除框框内指定行的信息
HEAD readhead(FILE *);//读取谱子文件的信息头
void HideCursor();//隐藏光标
void ShowCursor();//显示光标
char begin_page();//初始界面
char exit_page();//退出界面
char manual_page();//手动挡
char auto_page();//自动挡

int main(){
    system("mode con cols=180 lines=38"); //[8]
    short mode=0;
    while(1){   //所有页面的中转站
        if(mode==0){
            mode = begin_page();
        }
        if(mode==1){
            mode = manual_page();
        }
        if(mode==2){
            mode = auto_page();
        }
        if(mode==3){
            exit_page();
            break;
        }
        fflush(stdin);
    }
    return 0;
}

char exit_page(){
    HideCursor();
    char sentences[][MAXLEN]={"PROGRAMME DESIGN",\
        "名字 from 院系 in 学校",\
        "MUSIC RESOURCE",\
        "autopiano.cn",\
        "SPECIAL THANKS TO",\
        "Professor 老师",\
        "T.A. 助教1",\
        "T.A. 助教2",\
        "室友",\
        "github.com/WarpPrism/AutoPiano",\
        "runoob.com/cprogramming/c-tutorial.html",\
        "",\/*最后一段字符串由于没有下一段字符串来清掉它,会滞留在屏幕上,因此用空字符串来做最后一个*/
        "Thank You for Playing My Game!"\
    };
    print_kuang();
    short ystart=YSTART+DEPTHOFPAGE/2-11,line=0,sigofstr=0;
    int speed=500;
    for(line=YSTART+DEPTHOFPAGE-2;line+(sizeof(sentences)/MAXLEN-2)*2>YSTART;line--){
        for(sigofstr=0;sigofstr<sizeof(sentences)/MAXLEN-1;sigofstr++){
            if(kbhit()){
                speed = 0;   //快速跳过制作人员名单
            }
            if((line+sigofstr*2)<=YSTART+DEPTHOFPAGE-3&&(line+sigofstr*2)>=YSTART+2){
                cls_kuang(line+sigofstr*2,-1);
                cls_kuang(line+sigofstr*2,1);   //上下两行都清除一下
                gotoxy(XSTART+LENOFPAGE/2-strlen(sentences[sigofstr])/2,line+sigofstr*2);
                cout << sentences[sigofstr];
            }
        }
        Sleep(speed);  //滚动字幕的效果
    }
    for(line=YSTART+DEPTHOFPAGE-3;line>=YSTART+DEPTHOFPAGE/2-1;line--){
        cls_kuang(line,1);
        gotoxy(XSTART+LENOFPAGE/2-strlen(sentences[sizeof(sentences)/MAXLEN-1])/2,line);
        cout << sentences[sizeof(sentences)/MAXLEN-1];
        Sleep(speed);  //同上一条注释
    }
    gotoxy(XSTART+LENOFPAGE/2-strlen("请按任意键继续. . .")/2,YSTART+DEPTHOFPAGE-2);
    system("PAUSE");
    return 0;
}

char begin_page(){
    char line_one[]="Welcome to elec-piano!";
    char line_two[]="choose your mode:1.manual   2.auto   3.exit";
    print_kuang();
    gotoxy(XSTART+LENOFPAGE/2-strlen(line_one)/2,YSTART+DEPTHOFPAGE/2-3);   //将光标移到方框的正中央并打印文字
    cout << line_one;
    gotoxy(XSTART+LENOFPAGE/2-strlen(line_two)/2,YSTART+DEPTHOFPAGE/2-1);
    cout << line_two;
    gotoxy(XSTART+LENOFPAGE/2,YSTART+DEPTHOFPAGE/2+1);   //将光标移至中央
    char mode[127]={0};
    while(1){
        cin >> mode;     //输入检测
        while(getchar()!='\n'){
            continue;
        }
        if(mode[0]>='1'&&mode[0]<='3'&&strlen(mode)==1){
            break;
        }
        else{
            cls_kuang(YSTART+DEPTHOFPAGE/2+3,0);
            gotoxy(XSTART+LENOFPAGE/2-strlen("Input error!please try again:")/2,YSTART+DEPTHOFPAGE/2+1);
            cout << "Input error!please try again:" << endl;
            gotoxy(XSTART+LENOFPAGE/2,YSTART+DEPTHOFPAGE/2+3);
        }
    }
    system("CLS");
    return (mode[0]-'0');
}

char auto_page(){
    FILE *dir,*puzi,*puzi_hx;
    char sys_dir_msg[MAXLEN];
    char mus_namelist[50][MAXLEN]={0};
    short numofsong=0,ystart=YSTART+1,xstart=XSTART+1,lenofsongname=0;
    HEAD mus_info,hx_info;
    print_kuang();
    gotoxy(XSTART+1,ystart);
    cout << "Choose your music:";
    gotoxy(XSTART+1,++ystart);
    dir = _popen("dir .\\songs","r");
    while(!feof(dir)){
        fscanf(dir,"%s",sys_dir_msg);
        if(strstr(sys_dir_msg,".dat")!=NULL){//列出songs文件夹中的dat文件
            strcpy(mus_namelist[numofsong],sys_dir_msg);
            cout << ++numofsong << "." << sys_dir_msg;
            if(strlen(sys_dir_msg)>lenofsongname){
                lenofsongname = strlen(sys_dir_msg);
            }
            gotoxy(xstart,++ystart);
            if(ystart==DEPTHOFPAGE+YSTART-1){ //文件过多时换个行继续
                xstart += lenofsongname+5;
                ystart = YSTART+2;
                lenofsongname = 0;
                gotoxy(xstart,ystart);
            }
        }
    }
    fclose(dir);
    CwithI tempci;
    while(1){
        scanf("%9s",tempci.c);//输入检测
        while(getchar()!='\n'){
            continue;
        }
        tempci.c[9] = '\0';
        tempci.i = atoi(tempci.c);
        if(tempci.i==0||tempci.i>50||tempci.i<0){
            cls_kuang(ystart,1);
            cout << "Input Error!please try again:";
        }
        else{
            break;
        }
    }
    thread t(play_sound,'+');   //播放一段无声的MP3以加载播放器相关dll
    t.detach();
    gotoxy(XSTART+1,++ystart);
    char path_mode[50]="songs\\%s";
    char path[50]={0};
    char path_hx[50]={0};
    sprintf(path,path_mode,mus_namelist[tempci.i-1]);
    strcpy(path_hx,path);
    path_hx[strlen(path)-1] = 'x';
    path_hx[strlen(path)-2] = 'h';
    puzi = fopen(path,"r");
    
    if(puzi==NULL){
        cout << "File does not exist! Check your input";
        Sleep(2500);
        system("cls");
        return 0;
    }
    short hx_flag=1;
    puzi_hx = fopen(path_hx,"r");
    if(puzi_hx==NULL){
        hx_flag = 0;
    }
    else{
        hx_info = readhead(puzi_hx);
    }
    mus_info = readhead(puzi);
    
    system("cls");
    print_kuang();
    ystart=YSTART+1;
    gotoxy(XSTART+1,ystart);
    cout << "now play: " << mus_info.name;
    gotoxy(XSTART+1,++ystart);
    short flag=0;
    if(hx_flag==1){//有和弦时进入此分支
        while(1){
            thread t1(play_song,puzi,&ystart,mus_info,&flag);
            thread t2(play_song,puzi_hx,&ystart,hx_info,&hx_flag);
            t2.detach();
            t1.join();
            if(feof(puzi)||feof(puzi_hx)||flag==2||hx_flag==2){//其中一个谱子放完了自动跳出整个循环
                break;
            }
        }
    }
    else{
        while(1){
            thread t1(play_song,puzi,&ystart,mus_info,&flag);
            t1.join();
            if(feof(puzi)||flag==2){
                break;
            }
        }
    }
    fclose(puzi);
    if(hx_flag!=0){
        fclose(puzi_hx);
    }
    
    gotoxy(XSTART+1,++ystart);
    cls_kuang(ystart,1);
    cout << "end" << endl;
    cls_kuang(++ystart,1);
    
    system("PAUSE");
    system("CLS");
    return 0;
}

char manual_page(){
    HideCursor();
    print_kuang();
    print_pkeys();
    gotoxy(XSTART+1,YSTART+DEPTHOFPAGE-2);
    cout << "press Enter to quit the manual mode!";
    thread t(play_sound,'+');   //播放一段无声的MP3以加载播放器相关dll
    t.detach();
    int i=0;
    while(1){
        char keyboard_key;
        keyboard_key = getch(); //[2]
        if(keyboard_key=='\r'){
            break;     //按回车退出
        }
        thread t(play_sound,keyboard_key); //[3]
        t.detach();
        FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE)); //[4]
    }
    gotoxy(XSTART+LENOFPAGE/2-strlen("exit")/2,YSTART+DEPTHOFPAGE/2);
    cout << "exit!";
    ShowCursor();
    system("CLS");
    return 0;
}

void decoding_func(char keyboard_key,char *sound_name,short piano_type){ //在plays函数中被引用,可有效降低创建线程时传参的复杂程度
    char jian[]={'1','!','2','@','3','4','$','5','%','6','^','7','8','*','9','(','0','q','Q',\
        'w','W','e','E','r','t','T','y','Y','u','i','I','o','O','p','P','a','s','S','d','D',\
        'f','g','G','h','H','j','J','k','l','L','z','Z','x','c','C','v','V','b','B','n','m'}; //所有音名对应的按键
    char zhi_zimu[][3]={"C","Cs","D","Ds","E","F","Fs","G","Gs","A","As","B"}; //音名字母部分
    char zhi_shuzi[][2]={"0","1","2","3","4","5","6","7"};  //音名数字部分
    
    for(short i=0;i<sizeof(jian);i++){
        if(keyboard_key==jian[i]){
            short zimu_bianhao=i%12;   //字母部分12个一轮回
            short shuzi_bianhao=i/12;    //数字部分每十二个音+1
            char ss_zimu[5],ss_shuzi[2];
            strcpy(ss_zimu,zhi_zimu[zimu_bianhao]);
            strcpy(ss_shuzi,zhi_shuzi[shuzi_bianhao+piano_type]);  //带一个piano_type补正可以拓展音域
            strcat(ss_zimu,ss_shuzi);
            strcpy(sound_name,ss_zimu);
        }
        else{
            continue;
        }
    }
}

void play_sound(char keyboard_key){  
    char sound_name[5]={0};    //音名
    char temp_command[MAXLEN]={0};     //mciSendString的命令
    if(keyboard_key=='+'){
        strcpy(sound_name,"No_sound");    //播放一段无声的声音,用于加载与播放器有关的DLL文件
    }
    else{
        decoding_func(keyboard_key,sound_name,piano_type);   //将键盘上的键对应地解码成音名
    }
    sprintf(temp_command,"open piano\\%s.mp3 alias %s",sound_name,sound_name);
    mciSendStringA(temp_command,0,0,0); //[5] //打开音名.mp3
    sprintf(temp_command,"play %s",sound_name);
    mciSendStringA(temp_command,0,0,0);    //播放
    Sleep(10000);
    sprintf(temp_command,"close %s",sound_name);   //关闭
    mciSendStringA(temp_command,0,0,0);
    return;
}

void play_song(FILE *puzi,short *ystart,HEAD mus_info,short *flag){
    char keyboard_key;
    keyboard_key = fgetc(puzi);
    if(*flag==0){
        cout << keyboard_key;
    }
    if(keyboard_key=='|'||keyboard_key=='\n'){//遇到|和换行符时,由于不对乐曲本身发挥任何作用,因此需要特殊处理
        if(keyboard_key=='\n'&&(*flag)==0){
            if((*ystart)+1==DEPTHOFPAGE+YSTART-1){
                *ystart=YSTART+2;
                cls_kuang(*ystart,1);
            }
            else{
                if((*ystart)+2==DEPTHOFPAGE+YSTART-1){
                    (*ystart)++;
                    gotoxy(XSTART+1,*ystart);
                }
                else{
                    (*ystart)++;
                    cls_kuang(*ystart,1);
                }
            }
        }
        return;   
    }
    else{
        Sleep(mus_info.qusu.i);//此处控制曲速,注意:与一般音乐软件使用的曲速单位bpm不同,这里只是单纯的停顿一定毫秒
    }
    if(kbhit()){
        char kbout='\0';
        kbout = _getch();
        if(kbout=='\r'){ //播放中途按回车键退出
            *flag = 2;
            return;
        }
    }
    thread t(play_sound,keyboard_key);  //单独分出线程来播放声音
    t.detach();    
    return;
}

void gotoxy(int x,int y){    //[6]
    _COORD pos;
    pos.X=x;
    pos.Y=y;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),pos);  //设置鼠标位置
}

void print_kuang(){
    short start_x=XSTART,start_y=YSTART;
    short page_x=LENOFPAGE,page_y=DEPTHOFPAGE;
    gotoxy(start_x,start_y);      //将鼠标移动到起始点
    for(short y=0;y<page_y;y++){
        if(y==0||y==page_y-1){
            gotoxy(start_x,start_y+y);
            for(short x=0;x<=page_x;x++){
                cout << "=";     //若为第一行或最后一行,则打印page_x个=
            }
        }
        else{
            gotoxy(start_x,start_y+y);
            cout << '|';
            gotoxy(start_x+page_x,start_y+y);
            cout << '|';      //每行开头和末尾打印|
        }
    }
}

void print_pkeys(){
    short ystart=YSTART+1;
    gotoxy(XSTART+1,ystart);//普通的打印(很蠢)
    cout << "_________________________________________________________________________________________________________________________________________________";
    for(short i=0;i<6;i++){
        gotoxy(XSTART+1,++ystart);
        cout << "|  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |   |";
    }
    gotoxy(XSTART+1,++ystart);
    cout << "|  |!| |@|  |  |$| |%| |^|  |  |*| |(|  |  |Q| |W| |E|  |  |T| |Y|  |  |I| |O| |P|  |  |S| |D|  |  |G| |H| |J|  |  |L| |Z|  |  |C| |V| |B|  |   |";
    for(short i=0;i<2;i++){
        gotoxy(XSTART+1,++ystart);
        cout << "|  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |   |";
    }
    gotoxy(XSTART+1,++ystart);
    cout << "|  |_| |_|  |  |_| |_| |_|  |  |_| |_|  |  |_| |_| |_|  |  |_| |_|  |  |_| |_| |_|  |  |_| |_|  |  |_| |_| |_|  |  |_| |_|  |  |_| |_| |_|  |   |";
    for(short i=0;i<2;i++){
        gotoxy(XSTART+1,++ystart);
        cout << "|   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |";
    }
    gotoxy(XSTART+1,++ystart);
    cout << "| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | q | w | e | r | t | y | u | i | o | p | a | s | d | f | g | h | j | k | l | z | x | c | v | b | n | m |";
    gotoxy(XSTART+1,++ystart);
    cout << "| C2| D2| E2| F2| G2| A2| B2| C3| D3| E3| F3| G3| A3| B3| C4| D4| E4| F4| G4| A4| B4| C5| D5| E5| F5| G5| A5| B5| C6| D6| E6| F6| G6| A6| B6| C7|";
    gotoxy(XSTART+1,++ystart);
    cout << "|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|";
}

void cls_kuang(short line,short mode){    
    gotoxy(XSTART+1,line);//清除框框内的文字,比system(“cls”)更快
    for(short c=0;c<LENOFPAGE-1;c++){
        printf(" ");
    }
    gotoxy(XSTART+1,line+mode);//清除当前行数之外的另一行
    for(short c=0;c<LENOFPAGE-1;c++){
        printf(" ");
    }
    gotoxy(XSTART+1,line);//光标回到初始位置
}

void HideCursor(){  //[7]
    CONSOLE_CURSOR_INFO cursor;    //隐藏光标
    cursor.bVisible = FALSE;    
    cursor.dwSize = sizeof(cursor);    
    HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);    
    SetConsoleCursorInfo(handle, &cursor);
}

void ShowCursor(){
    CONSOLE_CURSOR_INFO cursor;    //显示光标
    cursor.bVisible = TRUE;    
    cursor.dwSize = sizeof(cursor);    
    HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);    
    SetConsoleCursorInfo(handle, &cursor);
}

HEAD readhead(FILE *puzi){  //读取曲谱文件的标头,获取曲速,曲名等信息
    char flag=0,keyboard_key,count=0; 
    char tempstr[MAXLEN]={0};
    HEAD temphead;
    while(!feof(puzi)){
        keyboard_key = fgetc(puzi);
        if(keyboard_key=='<'){
            flag++;      
            continue;
        }
        if(keyboard_key=='>'){
            count = 0;
            flag++;
            if(flag==2){
                strcpy(temphead.name,tempstr);
            }
            if(flag==4){
                strcpy(temphead.qusu.c,tempstr);
                temphead.qusu.i = atoi(temphead.qusu.c);
            }
            if(flag==6){
                strcpy(temphead.ver,tempstr);
                keyboard_key = fgetc(puzi);
                break;
            }
            memset(tempstr,'\0',sizeof(tempstr));
        }
        if(flag%2==1){
            tempstr[count++] = keyboard_key;
        }
    }
    return temphead;
}


你好,我是有问必答小助手,非常抱歉,本次您提出的有问必答问题,技术专家团超时未为您做出解答


本次提问扣除的有问必答次数,将会以问答VIP体验卡(1次有问必答机会、商城购买实体图书享受95折优惠)的形式为您补发到账户。


因为有问必答VIP体验卡有效期仅有1天,您在需要使用的时候【私信】联系我,我会为您补发。