/************************************************* * The PMW Music Typesetter - 3rd incarnation * *************************************************/ /* Copyright (c) Philip Hazel, 1991 - 2020 */ /* Written by Philip Hazel, starting November 1991 */ /* This file last modified: November 2020 */ /* This file contains part III of the code for reading in a PMW score file. It contains top-level code for reading in one bar on one stave. */ #include "pmwhdr.h" #include "readhdr.h" /* Key signatures tables giving the semitone offsets from C of the white notes to which accidentals apply, in order for conventional key signatures, for initializing baraccs. */ static uschar tp_sharporder[] = { 5,0,7,2,9,4,11 }; static uschar tp_flatorder[] = { 11,4,9,2,7,0,5 }; /* Values for baraccs for the different accidentals. */ static uschar ba_values[] = { 2, 4, 1, 0, 2, 3 }; /* Pitch offsets for custom keys */ static int ba_xkey_offsets[] = { 4, 5, 7, 9, 11, 12, 14, 4, 5, 7 }; /************************************************* * Initialize accidentals table * *************************************************/ /* The baraccs table is used to hold the number of semitones in the current accidental for a given "white note" pitch, to enable an absolute pitch to be calculated. To enable the table to be a byte table containing only positive values, the values are held offset by 2, so that, for example, 0 => double flat (-2), and 3 => sharp (+1). When transposition is happening, the baraccs table is used for the input values, and baraccs_tp for the output values. This function is called at the start of each bar, and also after [key] and [reset]. Arguments: ba the table that is to be set (baraccs or baraccs_tp) key the key signature Returns: nothing */ void read_initbaraccs(uschar *ba, int key) { int i; int value; /* Clear out the table to no accidentals */ for (i = 0; i < baraccs_len; i++) ba[i] = ba_values[ac_natural]; /* Handle conventional key signatures */ if (key < X_key) { int countacc = main_keysigtable[key]; uschar *ordertab; if (countacc >= 0) { ordertab = tp_sharporder; value = ba_values[ac_sharp]; } else { ordertab = tp_flatorder; value = ba_values[ac_flat]; countacc = -countacc; } /* Put in the key signature accidentals */ for (i = 0; i < baraccs_len; i += 12) { int j; for (j = 0; j < countacc; j++) ba[i+ordertab[j]] = value; } } /* Handle custom key signatures. The 10 values in the custom table refer to the 10 positions on a treble-clef stave; we don't need to know the clef in order to set up the right pitches. */ else { int j; uschar *p = main_xkeys[key - X_key]; /* Custom accidental list */ for (j = 0; j < 10; j++) { int offset = ba_xkey_offsets[j]; int ac = ba_values[p[j] & 0x7f]; /* Ignore half-accidental bit */ if (ac == ba_values[ac_natural]) continue; for (i = 0; i < baraccs_len; i += 12) ba[i + offset] = ac; } } } /************************************************* * Read up/down movement * *************************************************/ /* This is used for options for plets. On entry, read_ch should contain either 'u' or 'd', which may either be the first letter after / or might follow 'l' or 'r'. We don't come here for /lx and /rx, but they are mentioned in the error message for unknown letters because they are something that could have been present. Arguments: value1 pointer to where the value read is added value2 if not NULL, the value is added here as well Returns: nothing */ static void read_updown(int *value1, int *value2) { int sign, x; switch(read_ch) { case 'u': sign = 1; break; case 'd': sign = -1; break; default: error_moan(ERR37, "/l, /r, /lx, /rx, /lu, /ld, /ru or /rd"); next_ch(); return; } x = sign * read_movevalue(); *value1 += x; if (value2 != NULL) *value2 += x; } /************************************************* * Read one bar * *************************************************/ /* Called from read_go(), the top level reading control function. Arguments: none Returns: TRUE if not reached the end of the stave */ BOOL read_bar(void) { void *bardatastart; read_barlinestyle = stave_barlinestyle; read_initbaraccs(baraccs, stave_key); read_initbaraccs(baraccs_tp, stave_key_tp); stave_resetOK = FALSE; stave_string_followOK = FALSE; stave_barrepeatcount = 0; stave_barlength = stave_maxbarlength = stave_pletlen = 0; stave_noteflags &= ~nf_cuesize; stave_checklength = curmovt->check; if (stave_lastwasdouble) stave_checklength &= curmovt->checkdoublebars; stave_lastgracestem = 0; stave_lastwasdouble = stave_overbeam = FALSE; stave_firstinbar = TRUE; stave_hadnocount = FALSE; stave_tripletize = (stave_noteflags & nf_tripletize) != 0; stave_stemstackptr = stave_beamstackptr = 0; read_lastensuredtie = NULL; /* Complain if too many bars */ if (stave_barnumber > curmovt->maxbarcount) { error_moan(ERR36, curmovt->maxbarcount); return FALSE; } /* Update the bar number printing vector if necessary */ if (stave_totalnocount > (curmovt->barnovector)[stave_barnumber]) (curmovt->barnovector)[stave_barnumber] = stave_totalnocount; /* Fill in index to the bar's data */ (stavehead->barindex)[stave_barnumber] = store_nextitem(); /* If notes are switched off, insert another control for the benefit of the playing code, which assumes notes on at the start of each bar. */ if (!stave_notes) { b_notesstr *p = store_getitem(b_notes); p->value = FALSE; } /* If we are in an omitempty stave and the previous bar contained only an ibar or dbar item, or ended with an unusual barline style, we must insert a prevbar item here. */ if (stavehead->omitempty && (read_prev_had_dbar || read_prev_had_ibar || read_prev_barlinestyle != stave_barlinestyle)) { b_prevbarstr *p = store_getitem(b_prevbar); p->dbar = read_prev_had_dbar; p->ibar = read_prev_had_ibar; p->style = read_prev_barlinestyle; } /* Remember where the real data starts for detecting an empty bar */ bardatastart = store_nextitem(); /* This is one big loop which stops after an [endstave] directive, or at the end of file, or at the end of the bar. If nothing has been generated, reset the index to null instead of inserting an End item. */ for (;;) { sigch(); if (read_endstave || read_ch == EOF) break; /* exit the loop */ /* Deal with bar lines */ if (read_ch == '|') { next_ch(); if (read_ch == '|') /* Double or internal end bar */ { next_ch(); if (read_ch == '|') { next_ch(); (void)store_getitem(b_ebar); } else { (void)store_getitem(b_dbar); if (!curmovt->checkdoublebars) stave_checklength = FALSE; stave_lastwasdouble = TRUE; } } else if (read_ch == '?') /* Invisible bar */ { next_ch(); (void)store_getitem(b_ibar); } else if (isdigit(read_ch)) /* Specific bar line type */ { read_barlinestyle = read_integer(FALSE); } if (read_ch == '=') /* Continue beam over bar line */ { next_ch(); stave_overbeam = TRUE; } /* Cancel the ensured space for a tied chord with seconds at the end of a bar. */ if (read_lastensuredtie != NULL) read_lastensuredtie->value = 0; break; /* Exit the loop */ } /* Deal with a staff directive or other construction that can occur in square brackets. */ if (read_ch == '[') { error_skip = skip_KET; next_sigch(); for (;;) { /* If a name is already read, handle it, possibly repeatedly. Note that at the start of a stave we enter this procedure with '[' set and possible "name" in read_word. That is why this test comes first. */ while (read_stavedir) read_stavedirective(); sigch(); if (read_ch == ']') { next_ch(); break; } if (read_ch == EOF) break; /* Deal with the various things that can occur in brackets */ if (isalpha(read_ch)) { next_word(); read_stavedir = TRUE; } /* Try for accent defaulting */ else if (read_ch == '\\') { stave_accentflags = 0; stave_ornament = -1; next_ch(); for (;;) { accent *ap; sigch(); if (read_ch == '\\') { next_ch(); break; } /* End default */ /* Search the table of accents and ornaments */ for (ap = accent_chars; ap->string != NULL; ap++) { int i; int ln = (int)Ustrlen(ap->string); for (i = 0; i < ln; i++) if (read_chptr[i-1] != ap->string[i]) break; if (i >= ln) { read_chptr += ln - 1; next_ch(); break; } } /* Found in the table */ if (ap->string != NULL) { if (ap->flag < 256) stave_ornament = ap->flag; else stave_accentflags |= ap->flag; } /* Not found in the table */ else if (read_ch == 'a') { int x; next_ch(); error_skip = skip_OFF; /* Temporarily no skip */ if (read_expect_integer(&x, FALSE, FALSE)) { if (x <= dyn_max) stave_accentflags |= accent_list[x]; else error_moan(ERR128, x); } error_skip = skip_KET; } else { error_moan(ERR45); if (read_ch == ']') break; next_sigch(); } } if ((stave_accentflags & (af_staccato|af_staccatiss)) == (af_staccato|af_staccatiss)) error_moan(ERR129); } /* Deal with repeated bars; expect number > 0, but subtract one from it. If number is followed by nd, rd, or th, it is an nth time bar marking. */ else if (isdigit(read_ch)) { int n = read_integer(FALSE); if (n > 0) { int done = FALSE; sigch(); if (isalpha(read_ch)) { next_word(); if (Ustrcmp(read_word, "st") == 0 || Ustrcmp(read_word, "nd") == 0 || Ustrcmp(read_word, "rd") == 0 || Ustrcmp(read_word, "th") == 0) { b_nbarstr *p = store_getitem(b_nbar); p->x = p->y = 0; p->n = n; p->s = NULL; p->ssize = 0; /**** Not currently in use ****/ sigch(); while (read_ch == '/') { int xsign = 1; int ysign = 1; next_ch(); switch(read_ch) { case 'd': ysign = -1; /* Fall through */ case 'u': next_ch(); read_expect_integer(&n, TRUE, FALSE); p->y += n * ysign; break; case 'l': xsign = -1; /* Fall through */ case 'r': next_ch(); read_expect_integer(&n, TRUE, FALSE); p->x += n * xsign; break; /* One day we might want individual sizes for strings, but for the moment this is not implemented. */ /***************** case 's': next_ch(); read_expect_integer(&n, FALSE, FALSE); p->ssize = n; break; *****************/ case '\"': p->s = string_read(); break; default: error_moan(ERR10, "\"u\", \"d\", \"l\", \"r\", or quoted string"); break; } } done = TRUE; } else read_stavedir = TRUE; } /* Repeated bar */ if (!done) { stave_barrepeatcount = n - 1; stave_barrepeatptr = store_nextitem(); } } else error_moan(ERR10, "Number greater than zero"); } /* Deal with rehearsal string */ else if (read_ch == '\"') string_stavestring(TRUE); /* Unrecognized */ else error_moan(ERR10, "Staff directive"); } error_skip = skip_EOL; } /* Deal with items not in directive brackets. Note that '|' has been dealt with earlier. */ else switch (read_ch) { /* Curly brackets are used for the start and end of plets. The end is often dealt with in read_note, but can sometimes turn up here if stave directives intervene. */ case '{': if (stave_pletlen != 0) { error_moan(ERR38); next_ch(); } else { b_pletstr *p; int sign; int flags = 0; int adjustx = 0; int adjustyleft = stave_plety; int adjustyright = adjustyleft; next_sigch(); /* The length of each note in the plet will be multiplied by stave_pletsupnum, and divided by stave_pletlen times stave_pletsupden. */ stave_pletsupnum = 0; /* Indicates not explicitly set */ stave_pletsupden = 1; /* Normal case */ stave_pletlen = 3; /* Default to triplet */ /* Read an explicit specification */ if (isdigit(read_ch)) { stave_pletlen = read_integer(FALSE); /* First number */ /* A minus indicates that we are dividing a smaller number of notes than the default. This is accomplished by dividing by 2. */ if (read_ch == '-') { next_sigch(); stave_pletsupden = 2; } /* A slash indicates that the first number is really the number of notes we are dividing, and the real value of stave_pletlen follows. */ if (read_ch == '/' && isdigit(*read_chptr)) { stave_pletsupnum = stave_pletlen; next_ch(); stave_pletlen = read_integer(FALSE); } } /* If we are dividing into a power of two, assume we are dividing 3 into this number if a numerator was not provided; otherwise assume 2. */ if (stave_pletsupnum == 0) stave_pletsupnum = ((stave_pletlen & (-stave_pletlen)) == stave_pletlen)? 3 : 2; /* If the number of irregular notes is more than twice the number of regular notes, we double the numerator, because the irregulars must be the next note size down; similarly quadruple the numerator for even more notes. */ if (stave_pletlen >= 4*stave_pletsupnum) stave_pletsupnum *= 4; else if (stave_pletlen >= 2*stave_pletsupnum) stave_pletsupnum *= 2; /* Now deal with the options */ while (read_ch == '/') { next_ch(); switch(read_ch) { case 'a': flags &= ~plet_b; flags |= plet_a | plet_by; sign = +1; goto ABSPLET; case 'b': flags &= ~plet_a; flags |= plet_b | plet_by; sign = -1; ABSPLET: flags &= ~(plet_abs | plet_bn); adjustyleft = adjustyright = 0; next_sigch(); if (isdigit(read_ch)) { flags |= plet_abs; adjustyleft = adjustyright = sign * read_integer(TRUE); } break; case 'n': flags &= ~plet_by; flags |= plet_bn; next_sigch(); break; case 'x': flags |= plet_x; next_sigch(); break; case 'u': case 'd': read_updown(&adjustyleft, &adjustyright); break; case 'l': next_ch(); if (isdigit(read_ch)) adjustx -= read_integer(TRUE); else { if (read_ch == 'x') { flags |= plet_lx; next_ch(); } else read_updown(&adjustyleft, NULL); } break; case 'r': next_ch(); if (isdigit(read_ch)) adjustx += read_integer(TRUE); else { if (read_ch == 'x') { flags |= plet_rx; next_ch(); } else read_updown(&adjustyright, NULL); } break; default: error_moan(ERR37, "a, b, n, x, u, d, l or r"); next_sigch(); break; } sigch(); } /* If neither /a nor /b has been given, use the default flags */ if ((flags & (plet_a | plet_b)) == 0) flags |= stave_pletflags; /* Now generate the data block */ p = store_getitem(b_plet); p->pletlen = stave_pletlen; p->flags = flags; p->x = adjustx; p->yleft = adjustyleft; p->yright = adjustyright; } /* Prevent reset (but resets are forbidden inside plets anyway). */ stave_resetOK = FALSE; break; /* Ends of plets are often dealt with at the end of a note, but can occasionally arise here if another directive intervenes. */ case '}': if (stave_pletlen == 0) error_moan(ERR38); else { stave_pletlen = 0; (void)store_getitem(b_endplet); } next_ch(); break; /* Angle brackets signal hairpins */ case '>': case '<': { int flags = stave_hairpinflags; int width = stave_hairpinwidth; int type = read_ch; int ending = (type == '<' && stave_hairpinbegun == '<') || (type == '>' && stave_hairpinbegun == '>'); int y = ending? 0 : stave_hairpiny; int x = 0, h = 0, offset = 0; int slu = 0, sru = 0; next_ch(); while (read_ch == '/') { next_ch(); /* b is anomalous - /bar is always allowed, but /b only on beginning hairpins. */ if (read_ch =='b' && *read_chptr == 'a' && read_chptr[1] == 'r') { flags |= hp_bar; next_ch(); next_ch(); next_ch(); } else switch(read_ch) { case 'u': y += read_movevalue(); break; case 'd': y -= read_movevalue(); break; case 'l': if (*read_chptr == 'c') { next_ch(); offset -= read_movevalue(); } else x -= read_movevalue(); break; case 'r': if (*read_chptr == 'c') { next_ch(); offset += read_movevalue(); } else x += read_movevalue(); break; case 'h': next_ch(); h = 500; if (isdigit(read_ch)) h = read_integer(TRUE); flags |= hp_halfway; break; case 's': next_ch(); if (read_ch == 'l' || read_ch == 'r') { int sign, amount; int *a = (read_ch == 'l')? &slu : &sru; next_ch(); if (read_ch == 'u' || read_ch == 'd') { sign = (read_ch == 'u')? +1 : -1; } else { error_moan(ERR37, "u or d"); break; } next_ch(); if (!read_expect_integer(&amount, TRUE, FALSE)) break; *a += sign*amount; } else error_moan(ERR37, "\"slu\", \"sld\", \"sru\" or \"srd\""); break; default: if (!ending) { int sign; switch(read_ch) { case 'a': flags &= ~hp_below; sign = 1; goto ABSHP; case 'b': flags |= hp_below; sign = -1; ABSHP: y = 0; flags &= ~(hp_middle | hp_abs); next_ch(); if (isdigit(read_ch)) { flags |= hp_abs; y = sign * read_integer(TRUE); } break; case 'm': flags |= hp_below | hp_middle; next_ch(); break; case 'w': next_ch(); read_expect_integer(&width, TRUE, FALSE); break; default: error_moan(ERR37, "\"u\", \"d\", \"l\", \"r\", \"a\", \"b\", \"m\", \"w\", \"slu\", \"sru\" or \"h\""); break; } } else error_moan(ERR37, "\"u\", \"d\", \"l\", \"r\", \"su\" or \"h\""); break; } } if (stave_hairpinbegun) { b_hairpinstr *p = store_getitem(b_hairpin); p->opt = 0; if (ending) { p->flags = flags; p->x = x; p->y = y; p->offset = offset; p->su = stave_hairpinsru; p->h = h; } else p->flags = p->x = p->y = p->offset = p->su = p->h = 0; } if (ending) stave_hairpinbegun = 0; else { b_hairpinstr *p = store_getitem(b_hairpin); p->opt = stave_hairpinbegun = type; p->flags = flags; p->x = x; p->y = y; p->su = slu; p->h = h; p->offset = offset; p->width = width; stave_hairpinsru = sru; stave_resetOK = FALSE; } } break; /* A slash must be followed by another, for a caesura */ case '/': next_ch(); if (read_ch != '/') error_moan(ERR37, "\"/\" (to make // for caesura)"); else { (void)store_getitem(b_caesura); next_ch(); } break; /* Quotes introduce text */ case '\"': string_stavestring(FALSE); break; /* A colon can be a dotted bar or the end of a repeat. */ case ':': next_ch(); if (read_ch == ')') { (void)store_getitem(b_rrepeat); next_ch(); if (stave_barlength == 0) error_moan(ERR138, "End", "start"); /* Warning */ } else (void)store_getitem(b_dotbar); break; /* A semi-colon used to be a general separator, way back in early days. Later, it was used as a beam breaking character, but still kept as a separator. This meant that if a beam break was incorrectly placed, no warning was given. It is therefore no longer a general separator, unless the very old, undocumented OldBeamBreak option is turned on (don't know if anyone will every feed PMW files with that set, but you never know). */ case ';': if (!opt_oldbeambreak) error_moan(ERR5, "semicolon"); next_sigch(); break; /* Might as well give a similar error for a stray comma (which isn't old enough to be tied up with old beam breaks). */ case ',': error_moan(ERR5, "comma"); next_sigch(); break; /* A bracket can be the start of a repeat, or the start of a chord. We peek at the next character to make sure. */ case '(': if (*read_chptr == ':') { store_getitem(b_lrepeat); next_ch(); next_sigch(); if (read_ch == '|') error_moan(ERR138, "Start", "end"); /* Warning */ break; } /* Else fall through ... */ /* If all else fails, try to read a note */ default: read_note(); break; } } /* Special handling for omitempty bars. If there is nothing in the bar except an invisible or double bar specification, and/or if the barline style was specified, set the bar as empty, and set flags so that a prevbar block is created at the start of the next bar. */ if (stavehead->omitempty) { void *nextitem = store_nextitem(); bstr *p = bardatastart; read_prev_had_ibar = FALSE; read_prev_had_dbar = FALSE; read_prev_barlinestyle = stave_barlinestyle; while (p != nextitem) { int type = p->type; switch(type) { case b_Jump: p = (bstr *)(((b_Jumpstr *)p)->next); break; case b_ibar: read_prev_had_ibar = TRUE; break; case b_dbar: read_prev_had_dbar = TRUE; break; default: goto NORMALBAREND; } p = (bstr *)((uschar *)p + length_table[type]); } /* If control gets here, 'twas only ibar or dbar */ if (read_prev_had_ibar || read_prev_had_dbar || read_barlinestyle != stave_barlinestyle) { read_prev_barlinestyle = read_barlinestyle; bardatastart = nextitem; /* make empty */ } } NORMALBAREND: /* If nothing has been generated, reset the index to NULL. Otherwise, mark the end of the bar and, if required, check its length. Then terminate any incomplete beam and set the stems of any pending notes. */ if (bardatastart == store_nextitem()) { (stavehead->barindex)[stave_barnumber] = NULL; stave_barrepeatptr = NULL; /* for repeated nothing */ } else { b_Endstr *b = store_getitem(b_End); b->overbeam = stave_overbeam; b->barlinestyle = read_barlinestyle; /* Set stave_maxbarlength to the longest length encountered, allowing for [reset]s. */ if (stave_barlength > stave_maxbarlength) stave_maxbarlength = stave_barlength; /* Check length. If the bar contains tuplets of prime numbers greater than 13, there may be rounding errors because the length of a breve is not a multiple of, for example, 17. This can also happen with tuplets of other kinds that involve hemidemisemiquavers. In these cases we allow a small discrepancy. */ if (stave_checklength && stave_maxbarlength != 0) { int extra = stave_maxbarlength - stave_requiredbarlength; if (abs(extra) > TUPLET_ROUND) { format_movt = curmovt; error_moan(ERR49, stave_barnumber, curstave, (extra > 0)? "long":"short", abs(extra)); } } /* Deal with incomplete beams and unchosen stems */ if (stave_beaming) read_setbeamstems(); mac_setstackedstems(stave_laststemup? nf_stemup : 0); /* If tripletizing was set at any point in this bar, scan it for dotted- quaver groups and adjust the note lengths. Also handle dotted crotchet followed by two semiquavers. */ if (stave_tripletize) { b_notestr *first = (b_notestr *)((stavehead->barindex)[stave_barnumber]); if (first->type != b_note) first = misc_nextnote(first, NULL); while (first != NULL) { b_notestr *next = misc_nextnote(first, NULL); if (next == NULL) break; /* Both notes must be flagged for tripletizing */ if ((first->flags & next->flags & nf_tripletize) != 0) { b_notestr *third; if (first->length == (len_quaver * 3)/2 && next->length == len_squaver) { first->length = (len_crotchet * 2)/3; next->length = len_crotchet/3; first = misc_nextnote(next, NULL); continue; } third = misc_nextnote(next, NULL); if (third == NULL) break; if ((third->flags & nf_tripletize) != 0 && first->length == (len_crotchet * 3)/2 && next->length == len_squaver && third->length == len_squaver) { first->length = (len_crotchet * 4)/3; next->length = len_crotchet/3; third->length = len_crotchet/3; first = third; continue; } } /* No tripletizing this pair */ first = next; } } } /* Grumble if unclosed plet */ if (stave_pletlen != 0) error_moan(ERR83); /* Check for end of file and return FALSE at end of stave */ sigch(); read_endstave |= (read_ch == EOF); return !read_endstave; } /* End of read3.c */