/************************************************* * 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 IV of the code for reading in a PMW score file. It contains code for handling stave directives. The main function is at the bottom, preceded by a table of directives, which refer to the other functions. They all have the same interface: no arguments or results. The variable read_dir is set to point to the found directive, and in its data structure there may be up to two arguments. The action of each function is either to set up a new item and add it to the list (done by store_getitem()), and if necessary, fill in its data value(s), or to set flags or variables that affect the way the stave's data is to be read. */ #include "pmwhdr.h" #include "readhdr.h" /************************************************* * Static variables * *************************************************/ static uschar real_clef[] = { clef_treble, clef_soprano, clef_mezzo, clef_alto, clef_tenor, clef_cbaritone, clef_baritone, clef_bass, clef_deepbass, clef_treble, clef_treble, clef_treble, clef_treble, clef_treble, clef_bass, clef_bass }; static int clef_octave[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, -12, -12, 12, -12 }; static int read_assumeflag = FALSE; /************************************************* * Common routine for dataless item * *************************************************/ static void p_common(void) { (void)store_getitem(read_dir->arg1); } /************************************************* * Common routine for above/below * *************************************************/ static void p_above(void) { int flag = FALSE; b_charvaluestr *p = store_getitem(read_dir->arg1); next_word(); if (Ustrcmp(read_word, "above") == 0) flag = TRUE; else if (Ustrcmp(read_word, "below") != 0) error_moan(ERR10, "\"above\" or \"below\""); p->value = flag; } /************************************************* * Common routine for positive dimension * *************************************************/ static void p_pvalue(void) { sigch(); if (isdigit(read_ch)) { b_intvaluestr *p = store_getitem(read_dir->arg1); p->value = read_integer(TRUE); } else error_moan(ERR10, "Number"); } /************************************************* * Common routine for signed dimension * *************************************************/ static void p_svalue(void) { int x; b_intvaluestr *p; if (!read_expect_integer(&x, TRUE, TRUE)) return; p = store_getitem(read_dir->arg1); p->value = x; } /************************************************* * Common routine for font setting * *************************************************/ static void p_font(void) { int *p = (read_dir->arg1 == 0)? &stave_fbfont : (read_dir->arg1 == 1)? &stave_textfont : (read_dir->arg1 == 2)? &stave_ulfont : &stave_olfont; int f = font_fontword(FALSE); if (f >= 0) *p = f; } /************************************************* * Common routine for size setting * *************************************************/ static void p_size(void) { int size; int *p = (read_dir->arg1 == 0)? &stave_fbsize : (read_dir->arg1 == 1)? &stave_textsize : (read_dir->arg1 == 2)? &stave_ulsize : &stave_olsize; if (!read_expect_integer(&size, FALSE, FALSE)) return; if (--size < 0 || size >= MaxFontSizes) { error_moan(ERR39, MaxFontSizes); return; } *p = size; } /************************************************* * Common routine for fixed noteheads value * *************************************************/ static void p_nh(void) { b_noteheadsstr *p = store_getitem(b_noteheads); p->value = read_dir->arg1; stave_stemflag = nf_stem; } /************************************************* * Beamacc and Beamrit * *************************************************/ static void p_beamaccrit(void) { b_charvaluestr *p = store_getitem(read_dir->arg1); sigch(); if (isdigit(read_ch)) { int n = read_integer(FALSE); if (n != 2 && n != 3) error_moan(ERR10, "2 or 3"); else stave_accritvalue = n; } p->value = stave_accritvalue; } /************************************************* * Clef setting * *************************************************/ static void p_clef(void) { if (!read_assumeflag) { b_clefstr *p = store_getitem(b_clef); p->trueclef = read_dir->arg1; p->suppress = FALSE; } else { b_setclefstr *p = store_getitem(b_setclef); p->value = read_dir->arg1; read_assumeflag = FALSE; } stave_clef = real_clef[read_dir->arg1]; stave_clef_octave = clef_octave[read_dir->arg1]; sigch(); if (isdigit(read_ch) || read_ch == '-') { read_expect_integer(&stave_octave, FALSE, TRUE); stave_octave *= 12; } stave_lastbasenoteptr = NULL; } /************************************************* * Assume * *************************************************/ static const char *assume_list[] = { "alto", "baritone", "bass", "contrabass", "deepbass", "hclef", "key", "mezzo", "noclef", "soprabass", "soprano", "tenor", "time", "treble", "trebledescant", "trebletenor", "trebletenorb" }; static void p_assume(void) { usint i; next_word(); for (i = 0; i < (sizeof(assume_list)/sizeof(uschar *)); i++) if (Ustrcmp(read_word, assume_list[i]) == 0) { read_assumeflag = TRUE; read_stavedir = TRUE; return; } error_moan(ERR10, "Clef, key, or time setting"); } /************************************************ * Barlinestyle * ************************************************/ static void p_barlinestyle(void) { (void)read_expect_integer(&stave_barlinestyle, FALSE, FALSE); read_barlinestyle = stave_barlinestyle; /* For current bar */ /* The default, for use with totally empty bars, is the first style given. This isn't entirely satisfactory, but copes with most cases. */ if (stavehead->barlinestyle == 255) stavehead->barlinestyle = stave_barlinestyle; } /************************************************* * Barnumber * *************************************************/ static void p_barnum(void) { b_barnumstr *p = store_getitem(b_barnum); int flag = TRUE; int x = 0; int y = 0; sigch(); if (read_ch == '/') { while (read_ch == '/') { int sign, *a = NULL, b; next_ch(); switch (read_ch) { case 'u': sign = +1; a = &y; break; case 'd': sign = -1; a = &y; break; case 'l': sign = -1; a = &x; break; case 'r': sign = +1; a = &x; break; default: sign = 0; error_moan(ERR10, "/u, /d, /l, or /r"); break; } if (sign == 0) break; next_ch(); if (!read_expect_integer(&b, TRUE, TRUE)) break; *a = *a + sign *b; } } else if (isalpha(read_ch)) { next_word(); if (Ustrcmp(read_word, "off") == 0) flag = FALSE; else read_stavedir = TRUE; } p->flag = flag; p->x = x; p->y = y; } /************************************************* * Couple * *************************************************/ static void p_couple(void) { next_word(); if (Ustrcmp(read_word, "up") == 0) stave_couplestate = +1; else if (Ustrcmp(read_word, "down") == 0) stave_couplestate = -1; else if (Ustrcmp(read_word, "off") == 0) stave_couplestate = 0; else error_moan(ERR10, "\"up\", \"down\", or \"off\""); } /************************************************* * Cue * *************************************************/ static void p_cue(void) { stave_noteflags &= ~nf_cuedotalign; stave_noteflags |= nf_cuesize; sigch(); if (read_ch == '/') { next_ch(); next_word(); if (Ustrcmp(read_word, "dotalign") == 0) stave_noteflags |= nf_cuedotalign; else error_moan(ERR10, "\"dotalign\""); } } /************************************************* * Dots * *************************************************/ static void p_dots(void) { next_word(); if (Ustrcmp(read_word, "above") == 0) stave_noteflags &= ~nf_lowdot; else if (Ustrcmp(read_word, "below") == 0) stave_noteflags |= nf_lowdot; else error_moan(ERR10, "\"above\" or \"below\""); } /************************************************* * Doublenotes * *************************************************/ static void p_doublenotes(void) { stave_notenum *= 2; } /************************************************* * Draw * *************************************************/ static void p_draw(void) { tree_node *node; int argcount = 0; drawitem args [20]; sigch(); while (isdigit(read_ch) || read_ch == '-' || read_ch == '+' || read_ch == '\"') { if (read_ch == '\"') { args[++argcount].d.ptr = read_draw_text(); args[argcount].dtype = dd_text; } else { if (!read_expect_integer(&(args[++argcount].d.val), TRUE, TRUE)) break; args[argcount].dtype = dd_number; } sigch(); } next_word(); node = Tree_Search(draw_tree, read_word); if (node == NULL) error_moan(ERR70, read_word); else { b_drawstr *d = store_getitem(b_draw); d->overflag = read_dir->arg1; d->item = node; if (argcount == 0) d->args = NULL; else { int i; d->args = store_Xget((argcount+1)*sizeof(drawitem)); d->args[0].dtype = dd_number; d->args[0].d.val = argcount; for (i = 1; i <= argcount; i++) d->args[i] = args[i]; } } } /************************************************* * Endcue * *************************************************/ static void p_endcue(void) { stave_noteflags &= ~(nf_cuesize|nf_cuedotalign); } /************************************************* * Endline & Endslur * *************************************************/ static void p_endline(void) { int id = 0; sigch(); if (read_ch == '/') { next_ch(); if (read_ch != '=') error_moan(ERR10, "\"=\""); else { next_ch(); id = read_ch; next_ch(); } } if (stave_slurcount-- > 0) { b_endslurstr *p = store_getitem(b_endslur); p->id = id; } else { error_moan(ERR17, "end of slur or line - ignored"); stave_slurcount = 0; } } /************************************************* * Endstave * *************************************************/ /* This sets the global read_endstave flag, which is detected in the stave-reading code. */ static void p_endstave(void) { read_endstave = TRUE; } /************************************************* * Footnote * *************************************************/ static void p_footnote(void) { b_footnotestr *f = store_getitem(b_footnote); f->type = b_footnote; read_headfootingtext(&(f->h), rh_footnote); } /************************************************* * Hairpins * *************************************************/ static void p_hairpins(void) { stave_hairpinflags = stave_hairpiny = 0; next_word(); if (Ustrcmp(read_word, "below") == 0) stave_hairpinflags = hp_below; else if (Ustrcmp(read_word, "middle") == 0) stave_hairpinflags = hp_below | hp_middle; else if (Ustrcmp(read_word, "above") != 0) { error_moan(ERR10, "\"above\", \"below\", or \"middle\""); return; } /* Default adjustment is allowed for all three positions */ sigch(); if (read_ch == '+' || read_ch == '-') { (void)read_expect_integer(&stave_hairpiny, TRUE, TRUE); } /* Absolute value is allowed only for above and below */ else if ((stave_hairpinflags & hp_middle) == 0 && isdigit(read_ch)) { stave_hairpinflags |= hp_abs; stave_hairpiny = read_integer(TRUE); if ((stave_hairpinflags & hp_below) != 0) stave_hairpiny = -stave_hairpiny; } } /************************************************* * Hairpinwidth * *************************************************/ static void p_hairpinwidth(void) { (void)read_expect_integer(&stave_hairpinwidth, TRUE, FALSE); } /************************************************* * Halvenotes * *************************************************/ static void p_halvenotes(void) { if (stave_notenum > 1) stave_notenum /= 2; else stave_noteden *= 2; } /************************************************* * Key * *************************************************/ static void p_key(void) { int warn = curmovt->keywarn; int oldkey = stave_key_tp; int oldwidth, newwidth; stave_key = read_key(); read_initbaraccs(baraccs, stave_key); stave_key_tp = transpose_key(stave_key, stave_transpose); read_initbaraccs(baraccs_tp, stave_key_tp); sigch(); if (isalpha(read_ch)) { next_word(); if (Ustrcmp(read_word, "nowarn") == 0) warn = FALSE; else read_stavedir = TRUE; } oldwidth = misc_keywidth(oldkey | 64, stave_clef); newwidth = misc_keywidth(stave_key_tp, stave_clef); /* If both the old (cancellation) width and the new key width are zero, there's nothing we can do about warning. */ if (oldwidth == 0 && newwidth == 0) warn = FALSE; /* If not "assume" create a new key item, preceded by a cancellation key item if the new signature is empty and the old one is not. */ if (!read_assumeflag) { b_keystr *p = store_getitem(b_key); if (newwidth == 0 && oldwidth != 0) { p->key = oldkey | 64; p->warn = warn; p->suppress = FALSE; p = store_getitem(b_key); } p->key = stave_key_tp; p->warn = warn; p->suppress = FALSE; } /* "Assume": insert a change of key without any printing. */ else { b_setkeystr *p = store_getitem(b_setkey); p->value = stave_key_tp; read_assumeflag = FALSE; } } /************************************************* * Justify * *************************************************/ static void p_justify(void) { sigch(); if (read_ch == '+' || read_ch == '-') { while (read_ch == '+' || read_ch == '-') { b_justifystr *p; int opt = read_ch; int side; next_ch(); next_word(); sigch(); if (Ustrcmp(read_word, "top") == 0) side = just_top; else if (Ustrcmp(read_word, "bottom") == 0) side = just_bottom; else if (Ustrcmp(read_word, "left") == 0) side = just_left; else if (Ustrcmp(read_word, "right") == 0) side = just_right; else { error_moan(ERR10, "\"top\", \"bottom\", \"left\", or \"right\""); return; } p = store_getitem(b_justify); p->opt = opt; p->side = side; } } else error_moan(ERR10, "\"+\" or \"-\""); } /************************************************* * Linegap & Slurgap * *************************************************/ static void p_linegap(void) { b_linegapstr *p; tree_node *draw = NULL; gaptextstr *gaptext = NULL; drawitem *drawargs = NULL; int lineid = 0; int xadjust = 0; int hfraction = -1; int width = -1; /* Read the options */ sigch(); while (read_ch == '/') { int x; next_sigch(); switch (read_ch) { case '=': next_ch(); lineid = read_ch; next_sigch(); break; case 'd': if (Ustrncmp(read_chptr, "raw ", 4) == 0) { int argcount = 0; drawitem args[20]; read_chptr += 4; read_ch = ' '; sigch(); while (isdigit(read_ch) || read_ch == '-' || read_ch == '+' || read_ch == '\"') { if (read_ch == '\"') { args[++argcount].d.ptr = read_draw_text(); args[argcount].dtype = dd_text; } else { if (!read_expect_integer(&(args[++argcount].d.val), TRUE, TRUE)) break; args[argcount].dtype = dd_number; } sigch(); } if (argcount > 0) { int i; drawargs = store_Xget((argcount+1)*sizeof(drawitem)); drawargs[0].dtype = dd_number; drawargs[0].d.val = argcount; for (i = 1; i <= argcount; i++) drawargs[i] = args[i]; } next_word(); draw = Tree_Search(draw_tree, read_word); if (draw == NULL) error_moan(ERR70, read_word); } else error_moan(ERR10, "\"draw\""); break; case 'h': next_ch(); if (isdigit(read_ch)) { if (!read_expect_integer(&x, TRUE, FALSE)) return; hfraction = x; } else hfraction = 500; break; case 'l': next_ch(); if (!read_expect_integer(&x, TRUE, FALSE)) return; xadjust -= x; break; case 'r': next_ch(); if (!read_expect_integer(&x, TRUE, FALSE)) return; xadjust += x; break; case 'w': next_ch(); if (!read_expect_integer(&x, TRUE, FALSE)) return; width = x; break; case '\"': gaptext = store_Xget(sizeof(gaptextstr)); gaptext->text = string_check(string_read()); gaptext->flags = 0; gaptext->size = 0; gaptext->x = 0; gaptext->y = 0; while (read_ch == '/') { int size; next_ch(); switch (read_ch) { case 'b': if (Ustrncmp(read_chptr, "ox", 2) == 0) { next_ch(); next_ch(); next_ch(); gaptext->flags |= text_box; } else error_moan(ERR10, "/box, /ring, or /s"); break; case 'd': gaptext->y -= read_movevalue(); break; case 'l': gaptext->x -= read_movevalue(); break; case 's': next_ch(); read_expect_integer(&size, FALSE, FALSE); if (--size < 0 || size >= MaxFontSizes) { error_moan(ERR39, MaxFontSizes); size = 0; } gaptext->size = size; break; case 'r': if (Ustrncmp(read_chptr, "ing", 3) == 0) { next_ch(); next_ch(); next_ch(); next_ch(); gaptext->flags |= text_ring; } else gaptext->x += read_movevalue(); break; case 'u': gaptext->y += read_movevalue(); break; default: error_moan(ERR10, "/box, /ring, or /s"); break; } } break; default: error_moan(ERR10, "=, l, r, or w"); break; } sigch(); } if (stave_slurcount <= 0) error_moan(ERR17, "%sgap directive", (read_dir->arg1)? "slur":"line"); /* Width defaults to width of text or 4 points */ if (width < 0) { if (gaptext == NULL) width = 4000; else { int fontsize = mac_muldiv((curmovt->stavesizes)[curstave], ((curmovt->fontsizes)->fontsize_text)[gaptext->size], 1000); int *matrix = ((curmovt->fontsizes)->fontmatrix_text)[gaptext->size]; if (matrix != NULL) memcpy(font_transform, matrix, 4*sizeof(int)); width = font_stringwidth(gaptext->text, font_rm, fontsize) + fontsize; font_reset(); } } /* Get data block and fill it in. */ p = store_getitem(b_linegap); p->type = (read_dir->arg1)? b_slurgap : b_linegap; p->id = lineid; p->hfraction = hfraction; p->xadjust = xadjust; p->width = width; p->draw = draw; p->args = drawargs; p->gaptext = gaptext; } /************************************************* * Midichannel, Midipitch, Midivoice, * * Playvolume, Playtranspose * *************************************************/ /* These are all variations on the same theme. All of them create a play change item entry, with various different parameters. We start with a local subrouting that they can all use. Arguments: channel channel number void voice number note note pitch volume volumne transpose transpose value Returns: nothing */ static void makechange(int channel, int voice, int note, int volume, int transpose) { b_playchangestr *p = store_getitem(b_playchange); p->stave = curstave; p->barno = stave_barnumber; p->channel = channel; p->voice = voice; p->note = note; p->volume = volume; p->transpose = transpose; p->next = NULL; *read_lastplaychange = p; read_lastplaychange = &(p->next); } /*** Midichannel ***/ static void p_midichannel(void) { int channel; int voicenumber; int volume = 128; if (!read_expect_integer(&channel, FALSE, FALSE)) return; if (channel < 1 || channel > MIDI_MAXCHANNEL) { error_moan(ERR109, MIDI_MAXCHANNEL); return; } if (read_plainstring()) { if (read_word[0] == 0) voicenumber = 129; else /* => no change */ { if (read_word[0] == '#') voicenumber = Uatoi(read_word+1); else voicenumber = read_getmidinumber(midi_voicenames, read_word, US"voice"); if (voicenumber < 1 || voicenumber > 128) { error_moan(ERR109, "voice", 128); voicenumber = 1; } } if (read_ch == '/') { int vol; next_ch(); if (read_expect_integer(&vol, FALSE, FALSE)) { if (vol > 15) error_moan(ERR10, "Number between 0 and 15"); else volume = vol; } } } else voicenumber = 129; makechange(channel, voicenumber - 1, 128, volume, 0); /* 128 => no change */ } /*** Midivoice ***/ static void p_midivoice(void) { int voicenumber; if (read_plainstring()) { if (read_word[0] == 0) voicenumber = 129; else /* => no change */ { if (read_word[0] == '#') voicenumber = Uatoi(read_word+1); else voicenumber = read_getmidinumber(midi_voicenames, read_word, US"voice"); if (voicenumber < 1 || voicenumber > 128) { error_moan(ERR109, "voice", 128); voicenumber = 1; } } makechange(128, voicenumber - 1, 128, 128, 0); /* 128 => no change */ } else error_moan(ERR10, "string"); } /*** Midipitch ***/ static void p_midipitch(void) { int note; if (read_plainstring()) { if (read_word[0] == 0) note = 0; /* => no more forcing */ else if (read_word[0] == '#') note = Uatoi(read_word+1); else note = read_getmidinumber(midi_percnames, read_word, US"percussion instrument"); makechange(128, 128, note, 128, 0); /* 128 => no change */ } else error_moan(ERR10, "string"); } /*** Playtranspose ***/ static void p_playtranspose(void) { int transpose; if (!read_expect_integer(&transpose, FALSE, TRUE)) return; makechange(128, 128, 128, 128, transpose); } /*** Playvolume ***/ static void p_playvolume(void) { int volume; if (!read_expect_integer(&volume, FALSE, FALSE)) return; if (volume > 15) { error_moan(ERR10, "Number between 0 and 15"); return; } makechange(128, 128, 128, volume, 0); } /************************************************************************ ************************************************************************/ /************************************************* * Move & Rmove * *************************************************/ static void p_move(void) { int x; int y = 0; b_movestr *p; if (!read_expect_integer(&x, TRUE, TRUE)) return; sigch(); if (read_ch == ',') { next_ch(); if (!read_expect_integer(&y, TRUE, TRUE)) return; } p = store_getitem(b_move); p->x = x; p->y = y; p->relative = read_dir->arg1; } /************************************************* * Name * *************************************************/ /* The stave magnification is used only if an explicit size is given; otherwise the fixed size is used. */ static void p_name(void) { snamestr **pp, **savepp; BOOL reading_extra_strings = FALSE; sigch(); /* Handle [name ] */ if (isdigit(read_ch)) { b_namestr *p = store_getitem(b_name); p->n = read_integer(FALSE); return; } /* Else handle any number of pairs; either or both may be present in each case. Add onto any existing chain. This code is a mess because it was hacked to allow for drawings and then extra strings. */ pp = &(stavehead->stave_name); while (*pp != NULL) pp = &((*pp)->next); for (;;) { int size; uschar *ss; snamestr *p; /* Check for end of strings and drawings */ sigch(); if (read_ch != '\"' && (read_ch != 'd' || Ustrncmp(read_chptr, "raw ", 4) != 0)) break; /* Set up a stave name structure, either for a string or a drawing. Restart here for extra strings that are associated with a "main" string. */ RESTART_STRING: size = ff_offset_init; p = store_Xget(sizeof(snamestr)); *pp = p; pp = &(p->next); p->next = NULL; p->extra = NULL; p->text = NULL; p->drawing = NULL; p->flags = 0; /* Read a string with possible extra strings attached. */ if (read_ch == '\"') { p->text = ss = string_read(); string_check(ss); p->linecount = 1; while (*ss) if (*ss++ == '|') p->linecount += 1; while (read_ch == '/') { next_ch(); if (read_ch == 'c') { p->flags |= snf_hcentre; next_ch(); } else if (read_ch == 'm') { p->flags |= snf_vcentre; next_ch(); } else if (read_ch == 'e') { p->flags |= snf_rightjust; next_ch(); } else if (read_ch == 's') { next_ch(); if (read_expect_integer(&size, FALSE, FALSE)) { if (--size < 0 || size >= MaxFontSizes) error_moan(ERR39, MaxFontSizes); } else return; } else if (read_ch == 'v') { p->flags |= snf_vertical; next_ch(); } /* One or more additional strings may hang off the extra field; this allows for different options. Such strings must follow immediately. */ else if (read_ch == '\"') { if (!reading_extra_strings) { savepp = pp; reading_extra_strings = TRUE; } p->offset = size; pp = &(p->extra); goto RESTART_STRING; } else { error_moan(ERR10, "/c, /e, /m, /s or /v"); return; } } /* End of '/' loop */ p->offset = size; if (reading_extra_strings) { pp = savepp; reading_extra_strings = FALSE; } } /* Handle a drawing; might follow a string, so check again */ sigch(); if (read_ch == 'd' && Ustrncmp(read_chptr, "raw ", 4) == 0) { drawitem args[20]; drawitem *drawargs = NULL; int argcount = 0; tree_node *node; read_chptr += 4; read_ch = ' '; sigch(); while (isdigit(read_ch) || read_ch == '-' || read_ch == '+' || read_ch == '\"') { if (read_ch == '\"') { args[++argcount].d.ptr = read_draw_text(); args[argcount].dtype = dd_text; } else { if (!read_expect_integer(&(args[++argcount].d.val), TRUE, TRUE)) break; args[argcount].dtype = dd_number; } sigch(); } if (argcount > 0) { int i; drawargs = store_Xget((argcount+1)*sizeof(drawitem)); drawargs[0].dtype = dd_number; drawargs[0].d.val = argcount; for (i = 1; i <= argcount; i++) drawargs[i] = args[i]; } next_word(); node = Tree_Search(draw_tree, read_word); if (node == NULL) error_moan(ERR70, read_word); p->drawing = node; p->args = drawargs; } } } /************************************************* * Newmovement * *************************************************/ /* [newmovement] is unexpected here - give a tidy error message */ static void p_newmovement(void) { error_moan(ERR73); /* this stops processing */ } /************************************************* * Nocheck * *************************************************/ static void p_nocheck(void) { stave_checklength = FALSE; } /************************************************* * Nocount * *************************************************/ /* Set up the bar number vector now in case of an error in this bar. However, ignore if two nocounts in the same bar (causes big trouble and can happen if a bar line is accidentally omitted). */ static void p_nocount(void) { if (!stave_hadnocount) { if (++stave_totalnocount > (curmovt->barnovector)[stave_barnumber+1]) (curmovt->barnovector)[stave_barnumber+1] = stave_totalnocount; stave_hadnocount = TRUE; } } /************************************************* * Noteheads * *************************************************/ static void p_noteheads(void) { int nh; b_noteheadsstr *p; next_word(); stave_stemflag = nf_stem; if (Ustrcmp(read_word, "only") == 0) { stave_stemflag = 0; nh = nh_only; } else if (Ustrcmp(read_word, "direct") == 0) { stave_stemflag = 0; nh = nh_direct; } else if (Ustrcmp(read_word, "normal") == 0) nh = nh_normal; else if (Ustrcmp(read_word, "harmonic") == 0) nh = nh_harmonic; else if (Ustrcmp(read_word, "cross") == 0) nh = nh_cross; else if (Ustrcmp(read_word, "none") == 0) nh = nh_none; else { error_moan(ERR10, "\"normal\", \"harmonic\", \"cross\", \"none\", \"only\", or \"direct\""); return; } p = store_getitem(b_noteheads); p->value = nh; } /************************************************* * Notes * *************************************************/ static void p_notes(void) { int flag = FALSE; b_charvaluestr *p = store_getitem(b_notes); next_word(); if (Ustrcmp(read_word, "on") == 0) flag = TRUE; else if (Ustrcmp(read_word, "off") != 0) error_moan(ERR10, "\"on\" or \"off\""); stave_notes = p->value = flag; } /************************************************* * Notespacing * *************************************************/ /* There are three possible formats */ static void p_ns(void) { sigch(); if (read_ch == '*') /* Multiplicative */ { int f; b_nsmstr *p; next_ch(); if (!read_expect_integer(&f, TRUE, FALSE)) return; if (read_ch == '/') { int d; next_ch(); if (!read_expect_integer(&d, TRUE, FALSE)) return; f = mac_fdiv(f, d); } p = store_getitem(b_nsm); p->value = f; } else if (isdigit(read_ch) || read_ch == '+' || read_ch == '-') { /* Individual additive */ int i, x; b_nsstr *p = store_getitem(b_ns); for (i = 0; i < 8; i++) p->ns[i] = 0; for (i = 0; i < 8; i++) { sigch(); if (!isdigit(read_ch) && read_ch != '+' && read_ch != '-') break; if (!read_expect_integer(&x, TRUE, TRUE)) break; p->ns[i] = x; if (read_ch == ',') next_ch(); } if (i == 1) error_moan(ERR89); /* Single change only may be a typo: warn */ } else store_getitem(b_ens); /* Reset */ } /************************************************* * Octave * *************************************************/ static void p_octave(void) { int x; if (!read_expect_integer(&x, FALSE, TRUE)) return; stave_octave = 12*x; stave_lastbasenoteptr = NULL; } /************************************************* * Omitempty * *************************************************/ static void p_omitempty(void) { stavehead->omitempty = TRUE; } /************************************************* * Page * *************************************************/ static void p_page(void) { b_pagestr *p = store_getitem(b_page); sigch(); if (read_ch == '+') { p->relative = read_ch; next_ch(); } else p->relative = 0; read_expect_integer(&(p->value), FALSE, FALSE); } /************************************************* * Percussion * *************************************************/ static void p_percussion(void) { stavehead->stavelines = 128 + 1; /* 128 => no clefs or keys */ } /************************************************* * Printpitch * *************************************************/ static void p_printpitch(void) { sigch(); if (read_ch == '*') { stave_printpitch = 0; next_ch(); } else stave_printpitch = read_stavepitch(); } /************************************************* * Reset * *************************************************/ static void p_reset(void) { (void)store_getitem(b_reset); if (stave_beaming) read_setbeamstems(); if (stave_barlength > stave_maxbarlength) stave_maxbarlength = stave_barlength; if (!stave_resetOK) error_moan((stave_barlength == 0)? ERR67 : ERR34); else if (stave_pletlen) error_moan(ERR35); /* We do the action anyway, to prevent spurious over-long line errors */ read_initbaraccs(baraccs, stave_key); stave_barlength = 0; stave_resetOK = FALSE; } /************************************************* * Resume * *************************************************/ static void p_resume(void) { (void)store_getitem(b_resume); stave_suspended = FALSE; } /************************************************* * Rlevel * *************************************************/ static void p_rlevel(void) { (void)read_expect_integer(&stave_restlevel, TRUE, TRUE); if (opt_oldrestlevel) stave_restlevel *= 2; } /************************************************* * Rspace & Space * *************************************************/ static void p_rspace(void) { int x; b_spacestr *p; if (!read_expect_integer(&x, TRUE, TRUE)) return; p = store_getitem(b_space); p->value = x; p->relative = read_dir->arg1; } /************************************************* * Skip * *************************************************/ static void p_skip(void) { int x; if (!read_expect_integer(&x, FALSE, FALSE)) return; /* Abandon this bar if there is nothing in it, else terminate */ if ((stavehead->barindex)[stave_barnumber] == store_nextitem()) (stavehead->barindex)[stave_barnumber] = NULL; else { b_Endstr *b = store_getitem(b_End); b->overbeam = FALSE; b->barlinestyle = stave_barlinestyle; } /* Advance to the required bar */ stave_barnumber += x; (stavehead->barindex)[stave_barnumber] = store_nextitem(); } /************************************************* * Slur and line * *************************************************/ /* The basic slur structure is quite small; separate structures are used for sets of modifications. They are chained together for convenience, and a slurmod structure is created when necessary. The sequence number 0 means "the unsplit slur" while other counts are for parts of a split slur. For backwards compatiblity, we retain the following synonyms: sly = 1ry sry = 2ly slc = 1c src = 2c A local subroutine is used to find the relevant slurmod on the chain, or to create a new one if it isn't found. Arguments: sequence the sequence number anchor points to the anchor of the chain Returns: pointer to the required slurmod */ static b_slurmodstr * findmods(int sequence, b_slurmodstr **anchor) { b_slurmodstr *m = *anchor; while (m != NULL) { if (m->sequence == sequence) return m; m = m->next; } m = store_getitem(b_slurmod); memset(m, 0, sizeof(b_slurmodstr)); m->type = b_slurmod; m->next = *anchor; *anchor = m; m->sequence = sequence; return m; } /*** Slur ***/ static void p_slur(void) { b_slurstr *p; int slurid = 0; int flags = read_dir->arg1; int ally = 0; b_slurmodstr *modchain = NULL; b_slurmodstr *mods = NULL; sigch(); /* Loop to read the many options. */ while (read_ch == '/') { int *a, *b, x; next_sigch(); /* Some things may appear only before the first split number qualifier. */ if (mods != NULL && mods->sequence != 0) { if (strchr("=abeshiow", read_ch) != NULL) error_moan(ERR113, read_ch); } switch (read_ch) { case '=': next_ch(); slurid = read_ch; next_ch(); break; case 'a': flags &= ~(sflag_b | sflag_abs | sflag_lay); next_ch(); if (read_ch == 'o') { next_ch(); flags |= sflag_lay; } else if (isdigit(read_ch) || read_ch == '-') { if (!read_expect_integer(&x, TRUE, TRUE)) return; flags |= sflag_abs; ally += x; } break; case 'b': flags &= ~(sflag_abs | sflag_lay); flags |= sflag_b; next_ch(); if (read_ch == 'u') { next_ch(); flags |= sflag_lay; } else if (isdigit(read_ch) || read_ch == '-') { if (!read_expect_integer(&x, TRUE, TRUE)) return; flags |= sflag_abs; ally -= x; } break; case 'c': next_ch(); if (mods == NULL) mods = findmods(0, &modchain); if (read_ch == 'x') { next_ch(); flags |= sflag_cx; } else if (read_ch == 'i' || read_ch == 'o') { int s = read_ch == 'o'? +1 : -1; next_ch(); if (!read_expect_integer(&x, TRUE, FALSE)) return; mods->c += x*s; } else if (read_ch == 'l' || read_ch == 'r') { BOOL left = read_ch == 'l'; next_ch(); if (read_ch == 'u' || read_ch == 'd' || read_ch == 'l' || read_ch == 'r') { int cc = read_ch; next_ch(); if (!read_expect_integer(&x, TRUE, FALSE)) return; switch(cc) { case 'u': if (left) mods->cly += x; else mods->cry += x; break; case 'd': if (left) mods->cly -= x; else mods->cry -= x; break; case 'l': if (left) mods->clx -= x; else mods->crx -= x; break; case 'r': if (left) mods->clx += x; else mods->crx += x; break; } } else error_moan(ERR10, "clu, cld, cll, clr, cru, crd, crl, or crr"); } else error_moan(ERR10, "ci, co, clu, cld, cll, clr, cru, crd, crl, or crr"); break; case 'u': next_ch(); if (!read_expect_integer(&x, TRUE, FALSE)) return; if (mods == NULL || mods->sequence == 0) ally += x; else { mods->ly += x; mods->ry += x; } break; case 'd': next_ch(); if (!read_expect_integer(&x, TRUE, FALSE)) return; if (mods == NULL || mods->sequence == 0) ally -= x; else { mods->ly -= x; mods->ry -= x; } break; case 'e': flags |= sflag_e; next_ch(); break; case 'l': case 'r': if (mods == NULL) mods = findmods(0, &modchain); x = (read_ch == 'l')? 0 : 1; next_ch(); switch(read_ch) { case 'l': break; case 'r': x |= 2; break; case 'd': x |= 4; break; case 'u': x |= 6; break; default: x = -1; break; } next_ch(); if (read_ch == 'c') { next_ch(); if ((x & 4) == 0) x |= 8; else x = -1; } if (x < 0) { error_moan(ERR10, "lu, ld, ll, llc, lr, lrc, ru, rd, rl, rlc, rr, or rrc"); } else { int s; int *z = NULL; /* Stop compiler unset warning */ switch (x) /* 12-15 won't occur because c is only with left/right */ { case 0: /* ll */ case 2: /* lr */ z = &(mods->lx); x -= 1; /* -1 or +1 */ break; case 1: /* rl */ case 3: /* rr */ z = &(mods->rx); x -= 2; /* -1 or +1 */ break; case 4: /* ld */ case 6: /* lu */ z = &(mods->ly); x -= 5; /* -1 or +1 */ break; case 5: /* rd */ case 7: /* ru */ z = &(mods->ry); x -= 6; /* -1 or +1 */ break; case 8: /* llc */ case 10: /* lrc */ z = &(mods->lxoffset); x -= 9; /* -1 or +1 */ break; case 9: /* rlc */ case 11: /* rrc */ z = &(mods->rxoffset); x -= 10; /* -1 or +1 */ break; } if (!read_expect_integer(&s, TRUE, FALSE)) return; *z += x*s; } break; /* The s... options are obsolete, referring to the first splitting point in a way that was limited and confusing. Keep them for compatibility, though. */ case 's': next_ch(); if (read_ch == 'l' || read_ch == 'r') { int s = 0; int *z = NULL; b_slurmodstr *tempmods; if (read_ch == 'l') { tempmods = findmods(1, &modchain); a = &(tempmods->ry); b = &(tempmods->c); } else { tempmods = findmods(2, &modchain); a = &(tempmods->ly); b = &(tempmods->c); } next_ch(); if (read_ch == 'u' || read_ch == 'd') { s = (read_ch == 'u')? +1 : -1; z = a; } else if (read_ch == 'c') { next_ch(); if (read_ch != 'i' && read_ch != 'o') error_moan(ERR10, "slci or slco"); else { s = (read_ch == 'o')? +1 : -1; z = b; } } else error_moan(ERR10, "u, d, ci or co"); if (z != NULL) { next_ch(); if (!read_expect_integer(&x, TRUE, FALSE)) return; *z += s*x; } } else error_moan(ERR10, "sl.. or sr.."); break; case 'h': flags |= sflag_h; next_ch(); break; case 'i': flags |= sflag_i; next_ch(); if (read_ch == 'p') { flags |= sflag_idot; next_ch(); } break; case 'o': next_ch(); if (read_ch == 'l') flags |= sflag_ol; else if (read_ch == 'r') flags |= sflag_or; else error_moan(ERR10, "ol or or"); next_ch(); break; case 'w': flags |= sflag_w; next_ch(); break; default: if (isdigit(read_ch)) { int n = read_integer(FALSE); if (n == 0) error_moan(ERR37, "number greater than zero"); mods = findmods(n, &modchain); sigch(); } else error_moan(ERR10, "=, a, b, w, ci, co, d, e, u, lu, ld, ru, rd, h, i, ol, or, or number"); break; } sigch(); } /* We don't allow wiggly with line slurs */ if ((flags & sflag_w) != 0) { if ((flags & sflag_l) != 0) error_moan(ERR33, "lines"); } /* We don't support editorial marks on dotted or dashed slurs */ /* ... but they have been requested, even though they may end up drawing the editorial mark through a space ... if ((flags & sflag_e) != 0) { if ((flags & sflag_i) != 0) error_moan(ERR94); } */ /* Now output the slur proper, and count for nesting check. */ p = store_getitem(b_slur); p->flags = flags; p->id = slurid; p->ally = ally; p->mods = modchain; stave_slurcount++; } /************************************************* * Smove * *************************************************/ static void p_smove(void) { b_movestr *p; if (!read_expect_integer(&stave_smove, TRUE, TRUE)) return; p = store_getitem(b_move); p->x = stave_smove; p->y = 0; p->relative = stave_smove_relative = read_dir->arg1; } /************************************************* * Stavelines * *************************************************/ static void p_stavelines(void) { int n; if (!read_expect_integer(&n, FALSE, FALSE)) return; if (n > 6) error_moan(ERR10, "Number in the range 0-6"); else stavehead->stavelines = n; } /************************************************* * Stavespacing * *************************************************/ static void p_ss(void) { usint done[STAVE_BITVEC_SIZE]; sigch(); mac_initstave(done, 0); for (;;) { int spacing, stave; int opt = (read_ch == '+' || read_ch == '-')? '+' : ' '; if (!read_expect_integer(&spacing, TRUE, TRUE)) return; if (read_ch != '/') stave = curstave; else { if (opt != ' ' || spacing < 0 || (spacing%1000) != 0) { error_moan(ERR10, "Stave number"); return; } stave = spacing/1000; next_ch(); opt = (read_ch == '+' || read_ch == '-')? '+' : ' '; if (!read_expect_integer(&spacing, TRUE, TRUE)) return; } if (stave > MAX_STAVE) error_moan(ERR42, MAX_STAVE); else { b_ssstr *p = store_getitem(read_dir->arg1); p->opt = opt; p->stave = stave; p->value = spacing; } if (mac_teststave(done, stave)) error_moan(ERR106, stave, read_dir->name); mac_setstave(done, stave); sigch(); if (read_ch == ',') next_sigch(); if (read_ch != '+' && read_ch != '-' && !isdigit(read_ch)) break; } } /************************************************* * Stems/Ties * *************************************************/ static void p_stems(void) { int *p = (read_dir->arg1 == 1)? &stave_stemforce : &stave_ties; next_word(); if (Ustrcmp(read_word, "auto") == 0) *p = 0; else if (Ustrcmp(read_word, "up") == 0 || Ustrcmp(read_word, "above") == 0) *p = +1; else if (Ustrcmp(read_word, "down") == 0 || Ustrcmp(read_word, "below") == 0) *p = -1; else error_moan(ERR10, "\"auto\", \"above\", \"up\", \"below\", or \"down\""); } /************************************************* * Stemlength = Sl * *************************************************/ static void p_stemlength(void) { (void)read_expect_integer(&stave_stemlength, TRUE, TRUE); if (opt_oldstemlength) stave_stemlength *= 2; } /************************************************* * Suspend * *************************************************/ static void p_suspend(void) { (void)store_getitem(b_suspend); stave_suspended = TRUE; } /************************************************* * Systemgap * *************************************************/ static void p_sg(void) { b_sgstr *p; int opt, value; sigch(); opt = (read_ch == '+' || read_ch == '-')? '+' : ' '; if (!read_expect_integer(&value, TRUE, TRUE)) return; p = store_getitem(read_dir->arg1); p->opt = opt; p->value = value; } /************************************************* * Text * *************************************************/ static void p_text(void) { int sign = 1; next_word(); stave_textabsolute = 0; if (Ustrcmp(read_word, "underlay") == 0) stave_textflags = text_ul; else if (Ustrcmp(read_word, "overlay") == 0) stave_textflags = text_ul | text_above; else if (Ustrcmp(read_word, "fb") == 0) stave_textflags = text_fb; else { if (Ustrcmp(read_word, "above") == 0) stave_textflags = text_above; else if (Ustrcmp(read_word, "below") == 0) { stave_textflags = 0; sign = -1; } else { error_moan(ERR10, "\"underlay\", \"fb\", \"above\", or \"below\""); return; } /* Check for absolute setting */ sigch(); if (isdigit(read_ch)) { stave_textflags |= text_absolute; stave_textabsolute = sign*read_integer(TRUE); } } } /************************************************* * Time * *************************************************/ static void p_time(void) { int warn = curmovt->timewarn; int t = read_time(); /* returns 0 after giving error */ int tt = t; if (t == 0) return; /* If the time signature is followed by "->" then we read a second signature to which bars are to be musically stretched or compressed. */ sigch(); if (read_ch == '-' && *read_chptr == '>') { read_chptr++; next_ch(); tt = read_time(); if (tt == 0) tt = t; } /* Set up stretching numerator and denominator. So as not to waste time multiplying in the common case, indicate that with numerator == 0. */ stave_requiredbarlength = read_compute_barlength(tt); if (t == tt) stave_matchnum = 0; else { stave_matchnum = stave_requiredbarlength; stave_matchden = read_compute_barlength(t); } /* Now test for "nowarn". */ sigch(); if (isalpha(read_ch)) { next_word(); if (Ustrcmp(read_word, "nowarn") == 0) warn = FALSE; else read_stavedir = TRUE; } if (!read_assumeflag) { b_timestr *p = store_getitem(b_time); p->time = t; p->warn = warn; p->suppress = !curmovt->showtime; /* Suppress if notime */ } else { b_settimestr *p = store_getitem(b_settime); p->value = t; read_assumeflag = FALSE; } } /************************************************* * Transpose * *************************************************/ /* A stave transpose does not of itself change the key signature. This is a facility, not a bug! However, we must call the routine in order to set up the letter count for transposing notes. The yield is discarded. */ static void p_transpose(void) { int x; if (!read_expect_integer(&x, FALSE, TRUE)) return; if (stave_transpose == no_transpose) stave_transpose = 0; stave_transpose += x; if (abs(stave_transpose) > max_transpose) error_moan(ERR139, (stave_transpose == x)? "T":"Accumulated t", stave_transpose, max_transpose); /* Hard error */ (void)transpose_key(stave_key, stave_transpose); stave_lastbasenoteptr = NULL; } /************************************************* * Transposedacc * *************************************************/ static void p_transposedacc(void) { next_word(); if (Ustrcmp(read_word, "force") == 0) stave_transposedaccforce = TRUE; else if (Ustrcmp(read_word, "noforce") == 0) stave_transposedaccforce = FALSE; else error_moan(ERR10, "\"force\" or \"noforce\""); } /************************************************* * Tremolo * *************************************************/ static void p_tremolo(void) { b_tremolostr *p; int count = 2; int join = 0; sigch(); while (read_ch == '/') { next_ch(); if (read_ch == 'x' || read_ch == 'j') { int *xp = (read_ch == 'x')? &count : &join; next_ch(); if (!read_expect_integer(xp, FALSE, FALSE)) return; } else error_moan(ERR10, "\"x\" or \"j\""); sigch(); } (void)store_getitem(b_beambreak); p = store_getitem(b_tremolo); p->count = count; p->join = join; } /************************************************* * Tripletize * *************************************************/ static void p_tripletize(void) { sigch(); if (isalpha(read_ch)) next_word(); else Ustrcpy(read_word, "on"); if (Ustrcmp(read_word, "off") == 0) { stave_noteflags &= ~nf_tripletize; } else { if (Ustrcmp(read_word, "on") != 0) read_stavedir = TRUE; stave_noteflags |= nf_tripletize; stave_tripletize = TRUE; /* Check bar for tripletizing */ } } /************************************************* * Triplets * *************************************************/ static void p_triplets(void) { int hadone = FALSE; int flag = TRUE; b_charvaluestr *p = store_getitem(b_tripsw); for (;;) { next_word(); if (Ustrcmp(read_word, "above") == 0) { stave_pletflags &= ~plet_b; stave_pletflags |= plet_a; goto ADJUST; } else if (Ustrcmp(read_word, "below") == 0) { stave_pletflags &= ~plet_a; stave_pletflags |= plet_b; ADJUST: stave_plety = 0; stave_pletflags &= ~plet_abs; sigch(); if (read_ch == '+' || read_ch == '-') (void)read_expect_integer(&stave_plety, TRUE, TRUE); else if (isdigit(read_ch)) { stave_pletflags |= plet_abs; stave_plety = read_integer(TRUE); if ((stave_pletflags & plet_b) != 0) stave_plety = -stave_plety; } } else if (Ustrcmp(read_word, "auto") == 0) { stave_pletflags &= ~(plet_a | plet_b | plet_abs | plet_bn | plet_by); stave_plety = 0; } else if (Ustrcmp(read_word, "bracket") == 0) { stave_pletflags &= ~plet_bn; stave_pletflags |= plet_by; } else if (Ustrcmp(read_word, "nobracket") == 0) { stave_pletflags &= ~plet_by; stave_pletflags |= plet_bn; } else if (Ustrcmp(read_word, "off") == 0) flag = FALSE; else if (Ustrcmp(read_word, "on") == 0) flag = TRUE; else break; hadone = TRUE; } if (!hadone) { read_stavedir = TRUE; error_moan(ERR10, "\"above\", \"below\", \"auto\", \"[no]bracket\", \"on\", or \"off\""); } p->value = flag; } /************************************************* * Ulevel/Olevel * *************************************************/ /* Knows that ulevelstr has the same form as olevelstr; the actual type required is in the argument. */ static void p_uolevel(void) { b_ulevelstr *p; int autoflag; int value = 0; sigch(); if (read_ch == '*') { autoflag = TRUE; next_ch(); } else { if (!read_expect_integer(&value, TRUE, TRUE)) return; autoflag = FALSE; } p = store_getitem(read_dir->arg1); p->opt = autoflag; p->value = value; } /************************************************* * Table of stave directives * *************************************************/ static dirstr read_stavedirlist[] = { { "all", p_common, b_all, TRUE }, { "alto", p_clef, clef_alto, FALSE }, { "assume", p_assume, 0, TRUE }, { "baritone", p_clef, clef_baritone, FALSE }, { "barlinestyle", p_barlinestyle, 0, TRUE }, { "barnumber", p_barnum, 0, TRUE }, { "bass", p_clef, clef_bass, FALSE }, { "beamacc", p_beamaccrit, b_beamacc, FALSE }, { "beammove", p_svalue, b_offset, TRUE }, { "beamrit", p_beamaccrit, b_beamrit, FALSE }, { "beamslope", p_svalue, b_slope, TRUE }, { "bottommargin", p_pvalue, b_pagebots, TRUE }, { "bowing", p_above, b_bowing, TRUE }, { "breakbarline", p_common, b_breakbarline, TRUE }, { "cbaritone", p_clef, clef_cbaritone, FALSE }, { "comma", p_common, b_comma, FALSE }, { "contrabass", p_clef, clef_contrabass, FALSE }, { "copyzero", p_svalue, b_zcopy, TRUE }, { "couple", p_couple, 0, TRUE }, { "cue", p_cue, 0, TRUE }, { "deepbass", p_clef, clef_deepbass, FALSE }, { "dots", p_dots, 0, TRUE }, { "doublenotes", p_doublenotes,0, TRUE }, { "draw", p_draw, FALSE, FALSE }, { "el", p_endline, 0, TRUE }, { "endcue", p_endcue, 0, TRUE }, { "endline", p_endline, 0, TRUE }, { "endslur", p_endline, 0, TRUE }, { "endstaff", p_endstave, 0, TRUE }, { "endstave", p_endstave, 0, TRUE }, { "ensure", p_pvalue, b_ensure, FALSE }, { "es", p_endline, 0, TRUE }, { "fbfont", p_font, 0, TRUE }, { "fbtextsize", p_size, 0, TRUE }, { "footnote", p_footnote, 0, TRUE }, { "h", p_nh, nh_harmonic, TRUE }, { "hairpins", p_hairpins, 0, TRUE }, { "hairpinwidth", p_hairpinwidth, 0, TRUE }, { "halvenotes", p_halvenotes, 0, TRUE }, { "hclef", p_clef, clef_h, FALSE }, { "justify", p_justify, 0, TRUE }, { "key", p_key, 0, FALSE }, { "line", p_slur, sflag_l, FALSE }, { "linegap", p_linegap, FALSE, FALSE }, { "mezzo", p_clef, clef_mezzo, FALSE }, { "midichannel", p_midichannel,0, TRUE }, { "midipitch", p_midipitch, 0, TRUE }, { "miditranspose", p_playtranspose, 0, TRUE }, { "midivoice", p_midivoice, 0, TRUE }, { "midivolume", p_playvolume, 0, TRUE }, { "move", p_move, FALSE, FALSE }, { "name", p_name, 0, TRUE }, { "newline", p_common, b_newline, TRUE }, { "newmovement", p_newmovement,0, TRUE }, { "newpage", p_common, b_newpage, TRUE }, { "nocheck", p_nocheck, 0, TRUE }, { "noclef", p_clef, clef_none, FALSE }, { "nocount", p_nocount, 0, TRUE }, { "noteheads", p_noteheads, 0, TRUE }, { "notes", p_notes, 0, TRUE }, { "notespacing", p_ns, 0, TRUE }, { "ns", p_ns, 0, TRUE }, { "o", p_nh, nh_normal, TRUE }, { "octave", p_octave, 0, TRUE }, { "olevel", p_uolevel, b_olevel, TRUE }, { "olhere", p_svalue, b_olhere, TRUE }, { "oltextsize", p_size, 3, TRUE }, { "omitempty", p_omitempty, 0, TRUE }, { "overdraw", p_draw, TRUE, FALSE }, { "overlayfont", p_font, 3, TRUE }, { "page", p_page, 0, TRUE }, { "percussion", p_percussion, 0, TRUE }, { "playtranspose", p_playtranspose, 0, TRUE }, { "playvolume", p_playvolume, 0, TRUE }, { "printpitch", p_printpitch, 0, TRUE }, { "reset", p_reset, 0, TRUE }, { "resume", p_resume, 0, TRUE }, { "rlevel", p_rlevel, 0, TRUE }, { "rmove", p_move, TRUE, FALSE }, { "rsmove", p_smove, TRUE, FALSE }, { "rspace", p_rspace, TRUE, FALSE }, { "sgabove", p_sg, b_sgabove, TRUE }, { "sghere", p_sg, b_sghere, TRUE }, { "sgnext", p_sg, b_sgnext, TRUE }, { "skip", p_skip, 0, TRUE }, { "sl", p_stemlength, 0, TRUE }, { "slur", p_slur, 0, FALSE }, { "slurgap", p_linegap, TRUE, FALSE }, { "smove", p_smove, FALSE, FALSE }, { "soprabass", p_clef, clef_soprabass, FALSE }, { "soprano", p_clef, clef_soprano, FALSE }, { "space", p_rspace, FALSE, FALSE }, { "ssabove", p_ss, b_ssabove, TRUE }, { "sshere", p_ss, b_sshere, TRUE }, { "ssnext", p_ss, b_ssnext, TRUE }, { "stafflines", p_stavelines, 0, TRUE }, { "stavelines", p_stavelines, 0, TRUE }, { "stemlength", p_stemlength, 0, TRUE}, { "stems", p_stems, 1, TRUE }, { "suspend", p_suspend, 0, TRUE }, { "tenor", p_clef, clef_tenor, FALSE }, { "text", p_text, 0, TRUE }, { "textfont", p_font, 1, TRUE }, { "textsize", p_size, 1, TRUE }, { "tick", p_common, b_tick, FALSE }, { "ties", p_stems, 2, TRUE }, { "time", p_time, 0, FALSE }, { "topmargin", p_pvalue, b_pagetops, TRUE }, { "transpose", p_transpose, 0, TRUE }, { "transposedacc", p_transposedacc, 0, TRUE }, { "treble", p_clef, clef_treble, FALSE }, { "trebledescant", p_clef, clef_trebledescant, FALSE }, { "trebletenor", p_clef, clef_trebletenor, FALSE }, { "trebletenorb", p_clef, clef_trebletenorB, FALSE }, { "tremolo", p_tremolo, 0, TRUE }, { "tripletize", p_tripletize, 0, TRUE }, { "triplets", p_triplets, 0, TRUE }, { "ulevel", p_uolevel, b_ulevel, TRUE }, { "ulhere", p_svalue, b_ulhere, TRUE }, { "ultextsize", p_size, 2, TRUE }, { "unbreakbarline",p_common, b_unbreakbarline, TRUE }, { "underlayfont", p_font, 2, TRUE }, { "x", p_nh, nh_cross, TRUE }, { "xline", p_slur, sflag_x+sflag_l, FALSE }, { "xslur", p_slur, sflag_x, FALSE }, { "z", p_nh, nh_none, 0 } }; static int read_stavedirsize = sizeof(read_stavedirlist)/sizeof(dirstr); /************************************************* * Handle a stave directive * *************************************************/ /* The directive name is already in read_word. If processing this one reads one word ahead, it sets read_stavedir TRUE. Arguments: none Returns: nothing */ void read_stavedirective(void) { dirstr *first = read_stavedirlist; dirstr *last = first + read_stavedirsize; read_stavedir = FALSE; while (last > first) { int c; read_dir = first + (last-first)/2; c = Ustrcmp(read_word, read_dir->name); if (c == 0) { (read_dir->proc)(); if (!read_dir->arg2) stave_resetOK = FALSE; return; } if (c > 0) first = read_dir + 1; else last = read_dir; } error_moan(ERR32, read_word); } /************************************************* * Read a clef name * *************************************************/ /* This function is used by the printkey heading directive. It is here so that it can use the table above for the supported clefs, thus avoiding a duplicate list. Argument: none Returns: the key */ int read_clef(void) { dirstr *first, *last; next_word(); if (read_word[0] == 0) { error_moan(ERR105); return 0; } first = read_stavedirlist; last = first + read_stavedirsize; while (last > first) { int c; dirstr *d = first + (last-first)/2; c = Ustrcmp(read_word, d->name); if (c == 0) { if (d->proc == p_clef) return d-> arg1; break; } if (c > 0) first = d + 1; else last = d; } error_moan(ERR126, read_word); return 0; } /* End of read4.c */