📄 seqread.c
字号:
case '~': if (index < 2) { domacro(); if (token[fieldx]) fferror("Unexpected character"); } else fferror("Unexpected control"); break; case 'T': if (index < 2) fferror("Control expected"); dotime(); break; case 'V': if (index < 2) fferror("Control expected"); dovoice(); break; case 'N': if (index < 2) fferror("Control expected"); donextdur(); break; default: if (index < 2) fferror("Control expected"); dur = dodur(); break; } if (index == 1 && (macctrlnum[0] != macctrlnum[1] || macctrldef[0] != macctrldef[1])) { fferror("Controls do not match"); } } index++; } if (index < 3) fferror("Expected 2 controls and step size"); else { if (macctrldef[0]) { int i, j, n; n = 0; i = macctrlparmx[0]; j = macctrlparmx[1]; while (n < macctrlnum[0]) { if (macctrlparms[i] != macctrlparms[j]) break; n++; i++; j++; } if (n >= macctrlnum[0]) n = 0; /* Note: duration shortened to prevent overlap with next ramp */ insert_deframp(the_score, seqround(thetime), lineno, voice, seqround(stepsize), trunc(dur) - 1, macctrldef[0], macctrlnum[0], macctrlparms + macctrlparmx[0], n, macctrlparms[j]); } else { /* Note: duration shortened to prevent overlap with next ramp */ insert_ctrlramp(the_score, seqround(thetime), lineno, voice, seqround(stepsize), trunc(dur) - 1, macctrlnum[0], macctrlparmx[0], macctrlparmx[1]); } } /* advance the time only if an N field was given */ if (ndurp) thetime += ntime; else thetime += dur;}/***************************************************************************** dorate* Effect: parses a !rate command****************************************************************************/private void dorate(){ linex += scan(); if (!token[0]) fferror("rate number expected"); else { long oldrate = rate; rate = (int) scanint(); if (token[fieldx]) fferror("Only digits expected here"); if (rate == 0) { fieldx = 0; fferror("Rate 100 will be used here"); rate = 100L; } start = thetime; /* adjust dur in case it is inherited by next note */ dur = (dur * oldrate); dur = dur / rate; }}private void doset(vec_flag) boolean vec_flag;{ ndurp = FALSE; linex += scan(); if (!token[0]) fferror("Variable name expected"); else { struct symb_descr *desc = &HASHENTRY(lookup(token)); if (!desc->symb_type) fferror("Called function not defined"); else if (vec_flag && (desc->symb_type != vec_symb_type)) { fferror("This is not an array"); } else if (!vec_flag && (desc->symb_type != var_symb_type)) { fferror("This is not a variable"); } else { int numargs = 1 + vec_flag; int value[2]; int i; int *address = desc->ptr.intptr; value[0] = value[1] = 0; i = 0; while (TRUE) { linex += scan(); if (nullstring(token)) { break; } else if (isdigit(token[0]) || token[0] == '-' || token[0] == '+') { if (i < numargs) { value[i++] = (int) scansgnint(); if (token[fieldx]) fferror("Only digits expected here"); } else fferror(too_many_error); } else { switch (token[0]) { case 'T': fieldx = 1; dotime(); break; case 'V': fieldx = 1; dovoice(); break; case 'N': fieldx = 1; donextdur(); break; default: fieldx++; if (i < numargs) { value[i++] = seqround(dodur()); } else fferror(too_many_error); break; } } } if (vec_flag && i != 2) fferror("No index given"); if (vec_flag) { if (value[0] >= desc->size) { fferror("Subscript out of bounds"); return; } /* reduce to the seti case: */ address += value[0]; /* compute the vector address */ value[0] = value[1]; /* set up value[] and i as if */ i--; /* this were seti, not setv */ } if (i != 1) fferror("No value given"); insert_seti(the_score, seqround(thetime), lineno, voice, address, value[0]); /* advance the time only if an N field was given */ if (ndurp) thetime += ntime; } }}/***************************************************************************** dospecial* Effect: parses special (those starting with "!") commands****************************************************************************/private void dospecial(){ switch (issymbol()) { case sym_tempo: dotempo(); break; case sym_rate: dorate(); break; case sym_csec: /* adjust dur for inheritance by next note */ dur = (dur * 1000L) / time_scale; time_scale = 1000L; break; case sym_msec: dur = (dur * 100L) / time_scale; time_scale = 100L; break; case sym_seti: doset(FALSE); break; case sym_setv: doset(TRUE); break; case sym_call: docall(); break; case sym_ramp: doramp(); break; case sym_clock: doclock(); break; case sym_def: dodef(); break; case sym_end: end_flag = TRUE; break; default: fferror("Special command expected"); } parseend(); /* flush the rest of the line */}/***************************************************************************** dosymdur* Effect: parses a duration (^, %, S, I, Q, H, or W) command****************************************************************************/private time_type dosymdur(){ int i, dotcnt = 0; long dotfactor; time_type result = 0; for (i = 0; i < durtable_len; i++) { if (durtable[i].symbol == token[fieldx-1]) { /* the shift right is because durs are stored doubled because * otherwise a 64th note would have the value 75/2: */ result = precise(durtable[i].value) >> 1; break; } } if (i == durtable_len) { fieldx--; fferror("Duration expected: one of W, H, Q, I, S, %, or ^"); return 0L; } while (token[fieldx]) { if (token[fieldx] == 'T') { /* triplet notation */ result = (result * 2) / 3; /* lose a bit but avoid scale() */ fieldx++; } else if (token[fieldx] == '.') { /* dotted notation */ dotcnt++; fieldx++; } else if (token[fieldx] == '/') { long divisor; fieldx++; divisor = scanint(); if (divisor > 0) result = result / divisor; else fferror("non-zero integer expected"); } else if (isdigit(token[fieldx])) { /* numbers are multipliers */ result = result * scanint(); } else break; } dotfactor = 1L; for (i=1; i<=dotcnt; i++) dotfactor = dotfactor * 2; result = (2 * result) - (result / dotfactor); return scale(result, 100L, tempo); /* time in milliseconds */}/***************************************************************************** dotempo* Effect: parses a !tempo command****************************************************************************/private void dotempo(){ linex += scan(); if (!token[0]) fferror("Tempo number expected"); else { long oldtempo = tempo; tempo = scanint(); if (token[fieldx]) fferror("Only digits expected here"); if (tempo == 0) { fieldx = 0; fferror("Tempo 100 will be used here"); tempo = 100L; } start = thetime; /* adjust dur in case it is inherited by next note */ if (symbolic_dur_flag) { dur = (dur * oldtempo); dur = dur / tempo; } }}/***************************************************************************** dotime* Effect: parses a time (T) command* Implementation: see implementation of donextdur()****************************************************************************/private void dotime(){ if (isdigit(token[fieldx])) { thetime = precise(scanint()); thetime = scale(thetime, (ulong)time_scale, rate); if (token[fieldx] ) fferror("Only digits were expected here"); } else { fieldx++; thetime = dodur(); } thetime += start; /* time is relative to start */}/***************************************************************************** dovoice* Effect: parse a voice (V) command (the voice is the MIDI channel)****************************************************************************/private void dovoice(){ if (isdigit(token[fieldx])) { voice = (int) scanint(); if (token[fieldx]) fferror("V must be followed by digits only"); if (voice > MAX_CHANNELS) { char msg[40]; sprintf(msg, "number too high, using %d instead", MAX_CHANNELS); fferror(msg); voice = MAX_CHANNELS; } else if (voice < 1) { fferror("number too low, using 1 instead"); voice = 1; } } else fferror("No digit after V");}/***************************************************************************** fferror* Inputs:* char *s: an error message string* Effect:* prints the line with the error* puts a cursor (^) at the error location* prints the error message (s)* Implementation:* this routine prints a carat under the character that* was copied into token[fieldx]. E.g. if fieldx = 0, the* carat will point to the first character in the field.****************************************************************************/private void fferror(s) char *s;{ gprintf(ERROR, "%3d | %s", lineno, line); marker(linex-strlen(token)+fieldx+1+6); gprintf(ERROR, "Error: %s.\n", s);}/***************************************************************************** init* Effect:* initializes the state variables****************************************************************************/private void init(){ int i; end_flag = FALSE; /* initial (default) values for all state variables */ symbolic_dur_flag = TRUE; /* default dur is symbolic */ for (i = 0; i < nctrl; i++) { /* no initial control changes */ ctrlflag[i] = FALSE; ctrlval[i] = 0; } lineno = 0; pitch = seq_dflt_pitch; loud = seq_dflt_loud; voice = seq_dflt_voice; time_scale = 1000L; tempo = 100L; rate = 100L; dur = precise(600); /* default dur is quarter note */ thetime = precise(0); start = thetime; ntime = 0L; ticksize = 0L; artic = 100;}/***************************************************************************** ins_a_note* Returns:* boolean: TRUE on success, FALSE if not enough memory* Effect:* note events (if any) corresponding to the current line are inserted* Implementation:* if a note on should occur after a note off and doesn't, and the* two notes have the same pitch, then the note off can cancel the* note on. to make it unlikely that roundoff will cause this situation,* dur is decreased by one half of a clock tick before rounding.* also, phase2 gives precedence to note-offs that are simultaneous* with note-ons.****************************************************************************/private boolean ins_a_note(){ long the_dur = (trunc(dur) * artic + 50) / 100; int the_pitch = pitch; event_type note; if (rest_flag) the_pitch = NO_PITCH; note = insert_note(the_score, seqround(thetime), lineno, voice, the_pitch, the_dur, loud); if (!note) return FALSE; return TRUE; /* success! */}/***************************************************************************** ins_ctrls* Returns:* boolean: TRUE on success, FALSE if not enough memory* Effect:* control events corresponding to current line are inserted in score* Implementation:* ctrlflag[i] is TRUE if control i was specified in this line, so* insert one control change for each ctrlflag[i] that is TRUE****************************************************************************/private boolean ins_ctrls(){ int i; event_type ctrl; for (i = 1; i < nctrl; i++) { if (ctrlflag[i]) { ctrl = insert_ctrl(the_score, seqround(thetime), lineno, i, voice, ctrlval[i]); if (!ctrl) return FALSE; ctrlflag[i] = FALSE; ctrlval[i] = 0; } } return TRUE; /* success! */}/***************************************************************************** issymbol* Outputs: returns symbol number, or -1 if no match* Assumes: token[1] has the symbol to look up (token[0] == '!')****************************************************************************/private int issymbol(){ int i, symb_num; char *sym; for (symb_num = 0; symb_num < sym_n; symb_num++) { sym = ssymbols[symb_num]; i = 1; while (TRUE) { if (token[i] != *sym) break; if (*sym == 0) return symb_num; sym++; i++; } } return -1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -