/* *** mml2dat.c */ #include "baresir.h" #include #include struct PIECE piece; static int quarternote = 480; static int key = 0, sf = 0; static int lmeasure, lbeat, ntsig, dtsig; static int poffset, notelen, velocity; static int cumtime, lno; extern int tempo; static int sharpflat[2][12] = { { 2, 9, 4,11, 6, 1, 8, 3,10, 5,12, 7 }, { 6,11, 4, 9, 2, 7,12, 5,10, 3, 8, 1 }, }; static struct NOTE *prevnote; static int nn; static char buf[1000]; static int bp; #define STACKSIZE 100 #define SEQUENTIAL 0 // 直列モード #define PARALLEL 1 // 並列モード static struct PSTACK { // 直列/並列スタック int mode; // SEQUENTIAL/PARALLEL int start, current; // 開始時刻、終了時刻 struct NOTE *first; // 列の最初の NOTE; int poffset, notelen, velocity; // スコープ値 } pstack[STACKSIZE]; int stp = 0; struct MMLTRACK mmltrack[NTRACK], *mtrack; extern void endfailure(); static void mml_error(msg) char *msg; { int i; printf("%3d: %s\n", lno, buf); printf(" "); for (i=0; itrack = i; mtrack->channel = i; mtrack->instrument = 0; mtrack->cumtime = 0; mtrack->poffset = poffset; mtrack->notelen = notelen; mtrack->velocity = velocity; } mtrack = mmltrack; // track 0 mtrack->used = 1; setup_time(); } static int getn() { int n = 0; while (isdigit(buf[bp])) { n = n*10 + buf[bp] - '0'; bp++; } bp--; return(n); } static void mml_special() { int i; switch(buf[bp++]) { case 'k': case 'K': /* key signature */ sf = 0; if (buf[bp] == '+') { bp++; } else if (buf[bp] == '-') { sf = 1; bp++; } if (!isdigit(buf[bp])) mml_error("調は +/- の数で指定します"); key = buf[bp] - '0'; if (sf) key = -key; break; case 't': case 'T': /* time signature */ if (!isdigit(buf[bp])) mml_error("拍子記号: 数字がありません"); ntsig = getn(); bp++; if (buf[bp] != '/') { if (ntsig == 0) break; mml_error("拍子記号: '/' がありません"); } bp++; if (!isdigit(buf[bp])) mml_error("拍子記号: 数字がありません"); dtsig = buf[bp++] - '0'; if ((dtsig != 4) && (dtsig != 8)) mml_error("拍子記号: 分母は 4 または 8 です"); setup_time(); break; case 'm': case 'M': /* tempo */ i = getn(); if (i == 0) mml_error("テンポ指定が間違っています"); tempo = 1000000 * 60/i; break; case 'i': case 'I': /* instrument */ if (!isdigit(buf[bp])) mml_error("GM 楽器(音色)番号が必要です"); i = getn(); if (i > 0) i--; mtrack->instrument = i; break; default: mml_error("@ の後に正しくない文字があります"); } } static int mml_notelen(len) { if (buf[bp] == '=') { len = notelen; bp++; } if (isdigit(buf[bp])) { int n = getn(); bp++; switch (n) { case 1: len = quarternote * 4; break; case 2: len = quarternote * 2; break; case 4: len = quarternote * 1; break; case 8: len = quarternote / 2; break; case 16: len = quarternote / 4; break; case 32: len = quarternote / 8; break; case 64: len = quarternote /16; break; case 3: len = quarternote * 2/3; break; case 6: len = quarternote * 1/3; break; case 12: len = quarternote * 1/(3*2); break; case 24: len = quarternote * 1/(3*4); break; case 48: len = quarternote * 1/(3*8); break; case 96: len = quarternote * 1/(3*16); break; default: mml_error("音長の指定が間違っています"); } } AGAIN: switch(buf[bp]) { case '.': if (buf[bp+1] == '.') { len = len * 7 / 4; bp++; } else { len = len * 3 / 2; } break; case '_': len *= 2; bp++; goto AGAIN; case '/': len /= 2; bp++; goto AGAIN; case '+': bp++; len += mml_notelen(len); bp++; goto AGAIN; case '-': bp++; len -= mml_notelen(len); if (len < 0) len = 0; bp++; goto AGAIN; default: bp--; break; } return(len); } /* #ifndef abs #define abs(n) ((n < 0)? (-n): (n)) #endif */ static int mml_velocity() { int v = velocity; if ((buf[bp] != ':') && (buf[bp] != 'v') && (buf[bp] != 'V')) return(0); bp++; switch (buf[bp]) { case '+': bp++; v += getn(); break; case '-': bp++; v -= getn(); break; default: if (!isdigit(buf[bp])) { mml_error("強さの数値 (0-127) が必要です"); } v = getn(); } if (v > VMAX) v = VMAX; if (v < VMIN) v = VMIN; return(v); } void mml_measure(nt) struct NOTE *nt; { if (lmeasure > 0) { nt->measure = nt->offset / lmeasure + 1; nt->beat = (nt->offset % lmeasure) / lbeat + 1; } else { nt->measure = 0; nt->beat = nt->offset / lbeat + 1; } nt->boffset = nt->offset % lbeat; } static void mml_note() { int pitch, len, vel; switch (buf[bp++]) { case 'c': case 'C': pitch = 0; break; case 'd': case 'D': pitch = 2; break; case 'e': case 'E': pitch = 4; break; case 'f': case 'F': pitch = 5; break; case 'g': case 'G': pitch = 7; break; case 'a': case 'A': pitch = 9; break; case 'b': case 'B': pitch = 11; break; case 'r': case 'R': pitch = -1; goto NOTELEN; } pitch += poffset; switch (buf[bp]) { case '+': pitch++; if (buf[++bp] == '+') { pitch++; bp++; } break; case '-': pitch--; if (buf[++bp] == '-') { pitch--; bp++; } break; case '=': bp++; break; default: if (sharpflat[sf][pitch % 12] <= abs(key)) { if (sf) pitch--; else pitch++; } break; } NOTELEN: len = mml_notelen(notelen); vel = velocity; if (buf[bp+1] == ':') { bp++; vel = mml_velocity(); } if (pitch >= 0) { struct NOTE *nt = note_alloc(1); nn++; nt->pitch = pitch; nt->offset = cumtime; nt->duration = nt->span = len; nt->velocity = vel; mml_measure(nt); nt->track = mtrack->track; nt->channel = mtrack->channel; nt->instrument = mtrack->instrument; prevnote = nt; } else if (prevnote != NULL) { // rest prevnote->span += len; } cumtime += len; } static void mml_lpar(par) char par; { int mode = (par == '[')? PARALLEL: SEQUENTIAL; if (stp >= STACKSIZE) mml_error("stack overflow"); pstack[stp].poffset = poffset; pstack[stp].notelen = notelen; pstack[stp].velocity = velocity; stp++; pstack[stp].mode = mode; pstack[stp].start = cumtime; pstack[stp].current = cumtime; pstack[stp].first = note_alloc(0); pstack[stp].poffset = poffset; pstack[stp].notelen = notelen; pstack[stp].velocity = velocity; } static void mml_rpar(par) char par; { int mode = (par == ']')? PARALLEL: SEQUENTIAL; int start = pstack[stp].start; int span, len; if ((stp == 0) || (mode != pstack[stp].mode)) mml_error("閉じカッコが合っていません"); if (mode == PARALLEL) cumtime = pstack[stp].current; span = cumtime - start; bp++; len = mml_notelen(span); if (len != span) { struct NOTE *nt = pstack[stp].first; struct NOTE *last = note_alloc(0); cumtime = start + len; for (; nt < last; nt++) { nt->offset = (nt->offset - start)*len/span + start; nt->duration = nt->duration*len/span; nt->span = nt->span*len/span; mml_measure(nt); } } stp--; // recover nested values poffset = pstack[stp].poffset; notelen = pstack[stp].notelen; velocity = pstack[stp].velocity; } static void mml_track() { int i; { // save current track status mtrack->cumtime = cumtime; mtrack->poffset = poffset; mtrack->notelen = notelen; mtrack->velocity = velocity; } if (buf[bp] == '=') switch(buf[++bp]) { // synchronize tracks case '=': // current offset for (i=0; i cumtime)) cumtime = mmltrack[i].cumtime; for (i=0; i= NTRACK) mml_error("トラック番号の範囲は 0...15 です"); mtrack = mmltrack + i; { // set new track status mtrack->used = 1; cumtime = mtrack->cumtime; poffset = mtrack->poffset; notelen = mtrack->notelen; velocity = mtrack->velocity; } } void mmlseq() { int ch, ll; while (getln(buf) != NULL) { lno++; ll = strlen(buf); for (bp=0; bp pstack[stp].current) pstack[stp].current = cumtime; cumtime = pstack[stp].start; } else { pstack[stp].current = cumtime; } switch (buf[bp] & 0xff) { case '%': /* comment */ goto ENDLINE; case ' ': case '\t': case '\n': case '\r': continue; case 0xa1: // EUC blank if ((buf[bp+1] & 0xff) == 0xa1) { bp++; continue; } goto CERROR; case 0x81: // SJIS blank if ((buf[bp+1] & 0xff) == 0x40) { bp++; continue; } goto CERROR; case '@': /* special */ bp++; mml_special(); break; case 'a': case 'b': case 'c': case 'd': case 'A': case 'B': case 'C': case 'D': case 'e': case 'f': case 'g': case 'r': case 'E': case 'F': case 'G': case 'R': mml_note(); break; case 'l': case 'L': bp++; notelen = mml_notelen(notelen); break; case 'o': case 'O': if (!isdigit(buf[++bp])) mml_error("オクターブ番号が必要です"); poffset = (buf[bp] - '0' - 4)*12 + 60; break; case 'v': case 'V': if (buf[bp+1] == ':') bp++; velocity = mml_velocity(); break; case '<': poffset += 12; break; case '>': poffset -= 12; break; case '|': /* measure line */ if ((lmeasure > 0) && (cumtime % lmeasure)) mml_error("小節線が正しくありません"); break; case '[': case '{': // sequence mml_lpar(buf[bp]); break; case ']': case '}': mml_rpar(buf[bp]); break; case '#': // track manipulation bp++; mml_track(); break; default: CERROR: mml_error("正しくない文字が現れています"); break; } } ENDLINE: ; } if (stp > 0) { mml_error("カッコが閉じられていません"); } } struct PIECE * mml2dat() { mml_init(); mmlseq(); piece.key = (sf)? (-key): key; piece.ntime = ntsig; piece.dtime = dtsig; piece.lbeat = lbeat; piece.lmeasure = lmeasure; piece.cumtime = cumtime; piece.nn = nn; return(&piece); }