首页 > 其他分享 >一个使用Win32api的简单乐谱解析器

一个使用Win32api的简单乐谱解析器

时间:2023-01-14 11:55:17浏览次数:44  
标签:解析器 getch 乐谱 int note sleep __ SPEED Win32api

音调数据

enum scale {
    Rest = 0 , 
    A0  = 21 , A0s = 22 , B0  = 23 , 
	C1  = 24 , C1s = 25 , D1  = 26 , D1s = 27 , E1  = 28 , F1  = 29 , F1s = 30 , G1  = 31 , G1s = 32 , 
	A1  = 33 , A1s = 34 , B1  = 35 , 
	C2  = 36 , C2s = 37 , D2  = 38 , D2s = 39 , E2  = 40 , F2  = 41 , F2s = 42 , G2  = 43 , G2s = 44 , 
	A2  = 45 , A2s = 46 , B2  = 47 , 
	C3  = 48 , C3s = 49 , D3  = 50 , D3s = 51 , E3  = 52 , F3  = 53 , F3s = 54 , G3  = 55 , G3s = 56 , 
	A3  = 57 , A3s = 58 , B3  = 59 , 
	C4  = 60 , C4s = 61 , D4  = 62 , D4s = 63 , E4  = 64 , F4  = 65 , F4s = 66 , G4  = 67 , G4s = 68 , 
	A4  = 69 , A4s = 70 , B4  = 71 , 
	C5  = 72 , C5s = 73 , D5  = 74 , D5s = 75 , E5  = 76 , F5  = 77 , F5s = 78 , G5  = 79 , G5s = 80 , 
	A5  = 81 , A5s = 82 , B5  = 83 , 
	C6  = 84 , C6s = 85 , D6  = 86 , D6s = 87 , E6  = 88 , F6  = 89 , F6s = 90 , G6  = 91 , G6s = 92 , 
	A6  = 93 , A6s = 94 , B6  = 95 , 
	C7  = 96 , C7s = 97 , D7  = 98 , D7s = 99 , E7  = 100, F7  = 101, F7s = 102, G7  = 103, G7s = 104, 
	A7  = 105, A7s = 106, B7  = 107, 
	C8  = 108, 
};

enum voice {
    L1 = C3, L1s = C3s, L2 = D3, L2s = D3s, L3 = E3, L4 = F3, L4s = F3s, L5 = G3, L5s = G3s, L6 = A3, L6s = A3s, L7 = B3,
    M1 = C4, M1s = C4s, M2 = D4, M2s = D4s, M3 = E4, M4 = F4, M4s = F4s, M5 = G4, M5s = G4s, M6 = A4, M6s = A4s, M7 = B4,
    H1 = C5, H1s = C5s, H2 = D5, H2s = D5s, H3 = E5, H4 = F5, H4s = F5s, H5 = G5, H5s = G5s, H6 = A5, H6s = A5s, H7 = B5,
	SPEED_INTERVAL = 200, HIGH_SPEED = 300, 
	MIDDLE_SPEED = HIGH_SPEED + SPEED_INTERVAL, 
    LOW_SPEED = MIDDLE_SPEED + SPEED_INTERVAL, 
    HALF_SPEED = 0xef1, DOUBLE_SPEED = 0xef2, 
    _2 = 2, _4 = 4, _8 = 8, 
    __ = 0xff
};

主程序

//g++ ma_mu_play.cc -o ma_mu_play -lfmt -lwinmm -s
#include <fstream>
#include <fmt/core.h>
#include <Windows.h>
#include <map>
#include "ma_mu.h"

class music {
private:
    char *string = nullptr;
    int offset = 0;
    int line = 0;
    long size = 0;
    struct {
        int volume = 0x7f;
        int sleep = 300;
    } note;
    HMIDIOUT handle;
    bool is_note(char c) {
        if(c>=48&&c<56)
            return true;
        return false;
    }
    bool is_identifier(char c) {
        if( c == 'L' || c == 'H' || c == 'M' || \
            c == '+' || c == '-' || c == '#' || \
            c == ' ' || c == '\n'|| c == '\t'|| \
            is_note(c)
        )   return true;
        return false;
    }
    char getch() {
        return string[offset++];
    }
    void putch() {
        offset--;
    }
    bool play_note();
public:
    music() { };
    music(const char *);
    ~ music() {
        delete []string;
        midiOutClose(handle);
    };
    void print() {
        fmt::print(string);
    }
    void play() {
        while (play_note());
    }
};

music::music(const char *filename) {
    std::ifstream filestr;
    filestr.open (filename);
    std::filebuf *pbuf=filestr.rdbuf();
    size = pbuf->pubseekoff (0,std::ios::end,std::ios::in);
    pbuf->pubseekpos (0,std::ios::in);
    string=new char[size];
    pbuf->sgetn (string,size);
    filestr.close();
    
    midiOutOpen(&handle, 0, 0, 0, CALLBACK_NULL);
}

bool music::play_note() {
    char c = getch();
    //注释:一直读到行尾,下一字符为下一行第一个
    if(c=='@') {
        while (getch()!='\n');
        line++;
        return true;
    }
    if(!is_identifier(c))
        return false;
    //空字符:跳过
    if(c==' '||c=='\t')
        return true;
    if(c=='\n') {
        line++;
        return true;
    }
    
    //控制字符
    if (c == 'L' || c == 'H' || c == 'M') {
        if (c == 'L')
            note.sleep = LOW_SPEED;
        else if (c == 'H')
            note.sleep = HIGH_SPEED;
        else
            note.sleep = MIDDLE_SPEED;
        while (c != ',')
            c = getch();
        return true;
    }
    
    //----流程开始----
    //'  +#5/// ,'
    int note_segment = 1;   //初始8度
    int note_offset = 0;    //偏移
    int note_sleep = note.sleep;//Custom持续时间
    bool up_half_note = false;  //升半音
    
    //确定8度
    if(c == '+' || c == '-') {
        if (c == '+')
            note_segment = 2;
        else if (c == '-')
            note_segment = 0;
        c = getch();
    }
    
    //确定升半音
    if(c == '#') {
        up_half_note = true;
        c = getch();
    }
    
    if(!is_note(c)) {
        fmt::print("{}: {}: error! {}: {}: {}", __FILE__, __LINE__, offset, line, c);
        exit(0);
    }
    note_offset = c-48-1;   //偏移
    c = getch();
    
    //音符长度控制
    if(c=='.') {
        note_sleep *= 1.5;
        c = getch();
    } else
        while (c=='/') {
            note_sleep /= 2;
            c = getch();
        }
        
    if(c=='-') {
        int n = 0;
        while (c=='-') {
            n++;
            c = getch();
        }
        note_sleep += n * note.sleep;
    }
    
    while (c == ' '||c == '\t')
        c = getch();
    if (c!=',') {
        fmt::print("{}: {}: error! {}: {}: {}", __FILE__, __LINE__, offset, line, c);
        exit(0);
    }
    
    int note_table[3][7] = {
        {C3, D3, E3, F3, G3, A3, B3},
        {C4, D4, E4, F4, G4, A4, B4},
        {C5, D5, E5, F5, G5, A5, B5},
    };
    
    //等于0,则跳过
    if(note_offset>=0) {
        int note_value = note_table[note_segment][note_offset];
        if (up_half_note)
            ++note_value;
        int note_voice = (note.volume << 16) + (note_value << 8) + 0x94;
        //输出音调
        char tr[3] = {'L', 'M', 'H'};
        fmt::print("{:c}{:c}{:c}  {}\n", tr[note_segment], '1'+note_offset, up_half_note?'s':' ', note_sleep);
        midiOutShortMsg(handle, note_voice);
    }
    Sleep(note_sleep);
    return true;
}

void piano() {
	HMIDIOUT handle;
	midiOutOpen(&handle, 0, 0, 0, CALLBACK_NULL);
	std::map<char, int>v = {
		{'Z',C3},{'X',D3},{'C',E3},{'V',F3},{'B',G3},{'N',A3},{'M',B3},
		{'A',C4},{'S',D4},{'D',E4},{'F',F4},{'G',G4},{'H',A4},{'J',B4},
		{'Q',C5},{'W',D5},{'E',E5},{'R',F5},{'T',G5},{'Y',A5},{'U',B5},
	};
	while (1) {
		for (char i = 'A'; i <= 'Z'; i++) {
			if (GetKeyState(i) < 0) {
				midiOutShortMsg(handle, (0x007f << 16) + (v[i] << 8) + 0x90);
				while (GetKeyState(i) < 0)Sleep(100);
			}
		}
	}
}


int main (int argc, char** argv) {
    if(argc==2) {
        music mu(argv[1]);
        mu.play();
    } else
        piano();
    return 0;
}

标签:解析器,getch,乐谱,int,note,sleep,__,SPEED,Win32api
From: https://www.cnblogs.com/YHFBlogs/p/17051523.html

相关文章