📄 seqread.c
字号:
/***************************************************************************** marker* Inputs:* int count: the number of characters to indent* Effect: * prints a carat (^) at the position specified on file stderr****************************************************************************/private void marker(count)int count;{ int i; char s[128]; for (i=0; i<(count-1); s[i++]=' ') /* */ ; s[count-1] = '^'; s[count] = '\0'; gprintf(ERROR,"%s\n",s);}/****************************************************************** parseend* Effect:* parse the note terminator, either ",", ";", EOS or "\n"*****************************************************************/private void parseend(){ boolean done = FALSE; while (!done) { linex += scan1(&line[linex]); switch (token[0]) { case ',': ndurp = TRUE; /* switch that next time was specified */ ntime = 0L; done = TRUE; break; case ';': case '\n': case EOS: done = TRUE; break; case ' ': case '\t': break; /* skip over blanks and scan1 again */ default: fferror("Unexpected token"); linex += scan(); /* flush the token */ break; } }}/***************************************************************************** parsefield* Effect: looks at first character of token and calls a parsing routine*****************************************************************************/private void parsefield(){ fieldx = 1; switch (token[0]) { case 'T' : dotime(); break; case 'U': case 'W': case 'H': case 'Q': case 'S': case 'I': case '%': case '^': dur = dodur(); break; case 'R': do_a_rest(); break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': pitch = dopitch(); pitch_flag = TRUE; break; case 'P': pitch = doabspitch(); pitch_flag = TRUE; break; case 'L': loud = doloud(); break; case 'N': donextdur(); break;/* case 'J': * doctrl(1); * break; */ case 'K': doctrl(PSWITCH_CTRL); break; case 'M': doctrl(MODWHEEL_CTRL); break; case 'O': doctrl(TOUCH_CTRL); break; case 'X': doctrl(VOLUME_CTRL); break; case 'Y': doctrl(BEND_CTRL); break; case 'Z': doprogram(); break; case 'V': dovoice(); break; case '~': domacro(); break; case '*': docomment(); break; case '#': doartic(); break; default : doerror(); break; }}/***************************************************************************** parsenote* Effect: * parses a note line -- control events (if any) and note event (if* present) are inserted into score* Assumes:* line contains a string to be parsed****************************************************************************/private boolean parsenote(){ boolean out_of_memory = FALSE; int i; ndurp = FALSE; rest_flag = FALSE; /* this loop reads tokens for a note */ while (token[0]) { parsefield(); linex += scan(); } parseend(); /* take care of note terminator */ /* * insert ctrl's first so that will come before the note. */ if (ctrlflag[0]) { out_of_memory |= !ins_ctrls(); /* don't reset ctrlflag[0], it's used below */ } /* * insert macro's */ for (i = 0; i < macctrlx; i++) { event_type ctrl; if (macctrldef[i] == NULL) { ctrl = insert_macctrl(the_score, seqround(thetime), lineno, macctrlnum[i], voice, macctrlparmx[i]); } else { ctrl = insert_macro(the_score, seqround(thetime), lineno, macctrldef[i], voice, macctrlnum[i], &(macctrlparms[macctrlparmx[i]])); } out_of_memory |= (ctrl == NULL); } /* insert a note if * (1) a pitch was specified OR * (2) no control was specified and this is not a rest * (it's a pitch by default) * * NOTE: program changes during rests are advised since * synthesizers may not be able to process a program * change followed immediately by a note-on. In fact, this * is why we insert notes whose pitch is NO_PITCH -- so that * the program change can be processed during the rest. */ if (pitch_flag || (!ctrlflag[0] && !rest_flag && (macctrlx == 0))) { out_of_memory |= !ins_a_note(); } if (ndurp) thetime += ntime; else thetime += dur; return out_of_memory;}private boolean parseparm(valptr) long *valptr;{ register char c = token[fieldx]; if (isdigit(c) || c == '-') { *valptr = scansgnint(); return TRUE; } else { switch (c) { case 'P': fieldx++; *valptr = doabspitch(); return TRUE; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': fieldx++; *valptr = dopitch(); return TRUE; case 'U': case 'W': case 'H': case 'Q': case 'I': case 'S': case '%': case '^': fieldx++; *valptr = seqround(dodur()); return TRUE; case 'L': fieldx++; *valptr = doloud(); return TRUE; case '\'': fieldx++; *valptr = token[fieldx]; fieldx++; if (token[fieldx] != '\'') { fferror("single quote expected"); } fieldx++; return TRUE; default: fferror("Parameter expected"); return FALSE; } }}/***************************************************************************** scale* Inputs:* time_type x* int (ulong?) n, d* Outputs:* returns time_type: result of scaling x by n/d****************************************************************************/public time_type scale(x, n, d) ulong x; ulong n, d;{ ulong lo = (x & 0xFFFFL) * n; ulong hi = (x >> 16) * n; ulong res = hi / d; lo = (((hi - (res * d)) << 16) + lo + (d >> 1)) / d; return (time_type)( (res << 16) + lo );}/***************************************************************************** scan* Inputs:* char *start: the string to scan* Outputs:* returns int: the index of the next char in start to scan* Effect: * skips over leading blanks* copies characters from start into token, converting to upper case* scanning stops on delimiter: one of space, tab, newline, semicolon****************************************************************************/private int scan(){ char *start = line + linex; register char c; register int i = 0; register int j = 0; register int parens = 0; while (((c = start[i]) == ' ') || (c == '\t')) i++; while ((c = start[i]) != ' ' && c != '\n' && c != '\t' && c != EOS && (c != ',' || token[0] == '~' || parens > 0) && c != ';') { if (islower(start[i])) token[j] = toupper(start[i]); else token[j] = start[i]; if (c == '(') parens++; else if (c == ')') parens--; j++; i++; } token[j] = '\0'; fieldx = 0; if (parens) fferror("Unbalanced parens"); return i;}/***************************************************************************** scan1* Inputs:* char *start: the string to scan* Outputs:* returns int: the index of the next char in start to scan* Effect: * copies one char from start into token, converting to upper case****************************************************************************/private int scan1(start)char *start;{ int i = 0; token[0] = *start; if (islower(token[0])) token[0] = toupper(token[0]); if (!nullstring(token)) { token[1] = '\0'; i = 1; } fieldx = 0; return i;}/***************************************************************************** scanint* Outputs:* returns long: the scanned integer* Effect:* scans an unsigned long from token, starting at fieldx* fieldx is incremented to end of the integer****************************************************************************/private long scanint(){ long i = 0; char c; while ((c = token[fieldx])) { if (isdigit(c)) { i = (i*10) + (c - '0'); fieldx++; } else return i; } return i;}private long scansgnint(){ if (token[fieldx] == '-') { fieldx++; return -scanint(); } else { if (token[fieldx] == '+') { fieldx++; } return scanint(); }}/* scansymb -- scan a symbol from the token *//**/private void scansymb(str) char *str;{ char c; while ((c = token[fieldx])) { if (isdigit(c) || isalpha(c) || c == '_') { *str++ = c; fieldx++; } else break; } *str = EOS;}/***************************************************************************** seq_read* Inputs:* seq_type seq: the sequence to receive the score* FILE *fp: input file* Outputs:* none* Effect: * parses score from input file and builds score data structure****************************************************************************/void seq_read(seq, fp) seq_type seq; FILE *fp;{ boolean out_of_memory = FALSE; /* set when no more memory */ /* printf("seq_read: chunklist is 0x%x\n", seq->chunklist); */ the_score = seq; /* current sequence is a global within this module */ if (!seq) return; init(); lineno = 0; /* make sure line is well terminated or scan might run off the end */ line[linesize - 1] = EOS; line[linesize - 2] = '\n'; /* this loop reads lines */ while ((fgets(line, linesize - 2, fp) != NULL) && !out_of_memory && !check_aborted() && !end_flag) { lineno++; linex = 0; /* this loop reads notes from a line */ while ((line[linex] != EOS) && !out_of_memory) { /* loop invariant: line[linex] is first char of next note */ ctrlflag[0] = FALSE; /* other ctrlflags are reset by ins_ctrls() */ macctrlx = 0; macctrlnextparm = 0; pitch_flag = FALSE; linex += scan(); if (!nullstring(token)) { if (token[0] == '*') docomment(); else if (token[0] == '!') dospecial(); else out_of_memory = parsenote(); } else parseend(); } } if (out_of_memory) { gprintf(ERROR, "Out of note memory at line %d,\n", lineno-1); gprintf(ERROR, " the rest of your file will be ignored.\n"); } if (check_aborted()) { gprintf(ERROR, "User aborted score input,\n"); gprintf(ERROR, " the rest of your file will be ignored.\n"); if (abort_flag == BREAK_LEVEL) abort_flag = 0; } fclose(fp); gprintf(TRANS, "\nLoaded Adagio file with %ld note(s), %ld ctrl(s).\n\n", seq_notecount(the_score), seq_ctrlcount(the_score));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -