音调数据
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