/* * Music generator. * * This file is part of abcm2ps. * * Copyright (C) 1998-2019 Jean-François Moine (http://moinejf.free.fr) * Adapted from abc2ps, Copyright (C) 1996-1998 Michael Methfessel * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. */ #include #include #include #include "abcm2ps.h" struct STAFF_S staff_tb[MAXSTAFF]; /* staff table */ struct SYMBOL *tsnext; /* next line when cut */ float realwidth; /* real staff width while generating */ static int insert_meter; /* insert time signature (1) and indent 1st line (2) */ static float beta_last; /* for last short short line.. */ #define AT_LEAST(a,b) do { float tmp = b; if(ahead float hw_tb[] = {4.5, 5, 6, 8}; static int smallest_duration; /* upper and lower space needed by rests */ static char rest_sp[NFLAGS_SZ][2] = { {18, 18}, {12, 18}, {12, 12}, {8, 12}, {6, 8}, {10, 10}, /* crotchet */ {6, 4}, {10, 0}, {10, 4}, {10, 10} }; /* set the head of the notes */ static float set_heads(struct SYMBOL *s) { struct note *note; int i, m, n; char *p, *q, *r; float w, wmax; static float dx_tb[4] = { 7, 8, 10, 13.3 }; n = s->nhd; wmax = -1; for (m = 0; m <= n; m++) { note = &s->u.note.notes[m]; p = note->head; /* list of heads from parsing */ if (!p) continue; i = s->head; for (;;) { // search the head for the duration q = strchr(p, ','); if (!q) break; if (--i < 0) break; p = q + 1; } if (!q) q = p + strlen(p); r = strchr(p, '/'); if (r && r < q) { // search the head for the stem direction if (s->stem >= 0) q = r; else p = r + 1; } r = strchr(p, ':'); // width separator if (r && r < q) { q = r; sscanf(r, ":%f", &w); if (w > wmax) wmax = w; } note->head = p; note->hlen = q - p; } if (wmax < 0) { wmax = dx_tb[s->head]; if (s->dur >= BASE_LEN * 2 && s->head == H_OVAL) wmax = 13.8; } s->u.note.sdx = wmax / 2; // stem offset return wmax; } /* -- decide whether to shift heads to other side of stem on chords -- */ /* and set the head of the notes */ /* this routine is called only once per tune for normal notes * it is called on setting symbol width for grace notes */ static void set_head_shift(struct SYMBOL *s) { int i, i1, i2, n, sig, d, shift, ps; float dx, dx_max, dx_head; // unsigned char ax_tb[MAXHD], ac_tb[MAXHD]; /* distance for no overlap - index: [prev acc][cur acc] */ // static char dt_tb[4][4] = { // {5, 5, 5, 5}, /* dble sharp */ // {5, 6, 6, 6}, /* sharp */ // {5, 6, 5, 6}, /* natural */ // {5, 5, 5, 5} /* flat */ // }; /* set the heads of the notes with mapping */ dx_head = set_heads(s) + 2; n = s->nhd; if (n == 0) return; // single note /* set the head shifts */ dx = dx_head * 0.78; if (s->flags & ABC_F_GRACE) dx *= 0.5; sig = s->stem; if (sig >= 0) { i1 = 1; i2 = n + 1; ps = s->pits[0]; } else { dx = -dx; i1 = n - 1; i2 = -1; ps = s->pits[n]; } shift = 0; dx_max = 0; for (i = i1; i != i2; i += sig) { d = s->pits[i] - ps; ps = s->pits[i]; if (d == 0) { if (shift) { /* unison on shifted note */ float new_dx = s->u.note.notes[i].shhd = s->u.note.notes[i - sig].shhd + dx; if (dx_max < new_dx) dx_max = new_dx; continue; } if (i + sig != i2 /* second after unison */ //fixme: should handle many unisons after second && ps + sig == s->pits[i + sig]) { s->u.note.notes[i].shhd = -dx; if (dx_max < -dx) dx_max = -dx; continue; } } if (d < 0) d = -d; if (d > 3 || (d >= 2 && s->head < H_SQUARE)) { shift = 0; } else { shift = !shift; if (shift) { s->u.note.notes[i].shhd = dx; if (dx_max < dx) dx_max = dx; } } } s->xmx = dx_max; /* shift the dots */ } // set the accidental shifts for a set of chords static void acc_shift(struct note *notes[], int n, float dx_head) { int i, i1, ps, p1, acc; float dx, dx1; // set the shifts from the head shifts for (i = n - 1; --i >= 0; ) { // (no shift on top) dx = notes[i]->shhd; if (dx == 0 || dx > 0) continue; dx = dx_head - dx; ps = notes[i]->pit; for (i1 = n; --i1 >= 0; ) { if (!notes[i1]->acc) continue; p1 = notes[i1]->pit; if (p1 < ps - 3) break; if (p1 > ps + 3) continue; if (notes[i1]->shac < dx) notes[i1]->shac = dx; } } for (i = n; --i >= 0; ) { // from top to bottom acc = notes[i]->acc; if (!acc) continue; dx = notes[i]->shac; if (dx == 0) { dx = notes[i]->shhd; if (dx < 0) dx = dx_head - dx; else dx = dx_head; } ps = notes[i]->pit; for (i1 = n; --i1 > i; ) { if (!notes[i1]->acc) continue; p1 = notes[i1]->pit; if (p1 >= ps + 4) { // pitch far enough if (p1 > ps + 4) // if more than a fifth continue; switch (acc) { case A_NULL: case A_FT: case A_DF: continue; } switch (notes[i1]->acc) { case A_NULL: case A_FT: case A_DF: continue; } } if (dx > notes[i1]->shac - 6) { dx1 = notes[i1]->shac + 7; if (dx1 > dx) dx = dx1; } } notes[i]->shac = dx; } } /* set the horizontal shift of accidentals */ /* this routine is called only once per tune */ static void set_acc_shft(void) { struct SYMBOL *s, *s2; int i, staff, t, acc, n, nx; float dx_head; struct note *notes[MAXHD * 4]; // (max = 4 voices per staff) struct note *nt; s = tsfirst; while (s) { if (s->abc_type != ABC_T_NOTE || (s->flags & ABC_F_INVIS)) { s = s->ts_next; continue; } staff = s->staff; t = s->time; acc = 0; for (s2 = s; s2; s2 = s2->ts_next) { if (s2->time != t || s2->abc_type != ABC_T_NOTE || s2->staff != staff) break; if (acc) continue; for (i = 0; i <= s2->nhd; i++) { if (s2->u.note.notes[i].acc) { acc = 1; continue; } } } if (!acc) { s = s2; continue; } dx_head = set_heads(s) + 2; n = 0; for ( ; s != s2; s = s->ts_next) { for (i = 0; i <= s->nhd; i++) notes[n++] = &s->u.note.notes[i]; } // sort the notes for (;;) { nx = 0; for (i = 1; i < n; i++) { if (notes[i]->pit >= notes[i - 1]->pit) continue; nt = notes[i]; notes[i] = notes[i - 1]; notes[i - 1] = nt; nx++; } if (nx == 0) break; } acc_shift(notes, n, dx_head); } } /* -- unlink a symbol -- */ void unlksym(struct SYMBOL *s) { // if (!s->next) { // if (s->extra) { // s->type = FMTCHG; // s->aux = -1; // return; // } // } else { if (s->next) { s->next->prev = s->prev; // if (s->extra) { // struct SYMBOL *g; // // g = s->next->extra; // if (!g) { // s->next->extra = s->extra; // } else { // for (; g->next; g = g->next) // ; // g->next = s->extra; // } // } } if (s->prev) s->prev->next = s->next; else voice_tb[s->voice].sym = s->next; if (s->ts_next) { if (s->extra) { struct SYMBOL *g; g = s->ts_next->extra; if (!g) { s->ts_next->extra = s->extra; } else { for (; g->next; g = g->next) ; g->next = s->extra; } } if ((s->sflags & S_SEQST) && !(s->ts_next->sflags & S_SEQST)) { s->ts_next->sflags |= S_SEQST; s->ts_next->shrink = s->shrink; s->ts_next->space = s->space; } if (s->sflags & S_NEW_SY) s->ts_next->sflags |= S_NEW_SY; s->ts_next->ts_prev = s->ts_prev; } if (s->ts_prev) s->ts_prev->ts_next = s->ts_next; if (tsfirst == s) tsfirst = s->ts_next; if (tsnext == s) tsnext = s->ts_next; } /* -- check if voice combine may occur -- */ static int may_combine(struct SYMBOL *s) { struct SYMBOL *s2; int nhd2; s2 = s->ts_next; if (!s2 || s2->type != NOTEREST) return 0; if (s2->voice == s->voice || s2->staff != s->staff || s2->time != s->time || s2->dur != s->dur) return 0; if (s->combine <= 0 && s2->abc_type != s->abc_type) return 0; if (s->u.note.dc.n + s2->u.note.dc.n >= MAXDC) return 0; //fixme: should check the double decorations if (s->gch && s2->gch) return 0; if (s->abc_type == ABC_T_REST) { if (s2->abc_type == ABC_T_REST && (s->flags & ABC_F_INVIS) && !(s2->flags & ABC_F_INVIS)) return 0; return 1; } if (s2->ly || (s2->sflags & (S_SL1 | S_SL2)) || s2->u.note.slur_st != 0 || s2->u.note.slur_end != 0) return 0; if ((s2->sflags ^ s->sflags) & (S_BEAM_ST | S_BEAM_END)) return 0; nhd2 = s2->nhd; if (s->nhd + nhd2 + 1 >= MAXHD) return 0; if (s->combine <= 1 && s->pits[0] <= s2->pits[nhd2] + 1) return 0; return 1; } /* -- combine 2 voices -- */ static void do_combine(struct SYMBOL *s) { struct SYMBOL *s2; int i, m, nhd, nhd2, type; again: nhd = s->nhd; s2 = s->ts_next; s2->extra = NULL; if (s->abc_type != s2->abc_type) { /* if note and rest */ if (s2->abc_type != ABC_T_REST) { s2 = s; s = s2->ts_next; } goto delsym2; } if (s->abc_type == ABC_T_REST) { if ((s->flags & ABC_F_INVIS) && !(s2->flags & ABC_F_INVIS)) s->flags &= ~ABC_F_INVIS; goto delsym2; } /* combine the voices */ nhd2 = s2->nhd + 1; memcpy(&s->u.note.notes[nhd + 1], s2->u.note.notes, sizeof s->u.note.notes[0] * nhd2); memcpy(&s->pits[nhd + 1], s2->pits, sizeof s->pits[0] * (nhd2 + 1)); s->sflags |= s2->sflags & (S_SL1 | S_SL2 | S_TI1); nhd += nhd2; s->nhd = nhd; sort_pitch(s); /* sort the notes by pitch */ if (s->combine >= 3) { // remove unison heads for (m = nhd; m > 0; m--) { if (s->u.note.notes[m].pit == s->u.note.notes[m - 1].pit && s->u.note.notes[m].acc == s->u.note.notes[m - 1].acc) { i = nhd - m; if (i > 0) { memmove(&s->u.note.notes[m], &s->u.note.notes[m + 1], sizeof s->u.note.notes[0] * i); memmove(&s->pits[m], &s->pits[m + 1], sizeof s->pits[0] * i); } s->nhd = --nhd; } } } s->ymx = 3 * (s->pits[nhd] - 18) + 4; s->ymn = 3 * (s->pits[0] - 18) - 4; /* force the tie directions */ type = s->u.note.notes[0].ti1; if ((type & 0x0f) == SL_AUTO) s->u.note.notes[0].ti1 = SL_BELOW | (type & ~SL_DOTTED); type = s->u.note.notes[nhd].ti1; if ((type & 0x0f) == SL_AUTO) s->u.note.notes[nhd].ti1 = SL_ABOVE | (type & ~SL_DOTTED); delsym2: if (s2->text && !s->text) { s->text = s2->text; s->gch = s2->gch; } if (s2->u.note.dc.n > 0) { // update the added decorations int n; for (i = 0; i < s2->u.note.dc.n; i++) { if (s2->u.note.dc.tm[i].m >= 0) s2->u.note.dc.tm[i].m += nhd + 1; } n = s->u.note.dc.n; memcpy(&s->u.note.dc.tm[n], s2->u.note.dc.tm, sizeof s->u.note.dc.tm[0] * s2->u.note.dc.n); s->u.note.dc.n += s2->u.note.dc.n; } unlksym(s2); /* remove the next symbol */ /* there may be more voices */ if (!(s->sflags & S_IN_TUPLET) && may_combine(s)) goto again; } /* -- try to combine voices */ static void combine_voices(void) { struct SYMBOL *s, *s2, *g; int i, r; for (s = tsfirst; s->ts_next; s = s->ts_next) { if (s->combine < 0) continue; if (s->combine == 0 && s->abc_type != ABC_T_REST) continue; if (s->sflags & S_IN_TUPLET) { g = s->extra; if (!g) continue; /* tuplet already treated */ r = 0; for ( ; g; g = g->next) { if (g->type == TUPLET && g->u.tuplet.r_plet > r) r = g->u.tuplet.r_plet; } if (r == 0) continue; i = r; for (s2 = s; s2; s2 = s2->next) { if (!s2->ts_next) break; if (s2->type != NOTEREST) continue; if (!may_combine(s2)) break; if (--i <= 0) break; } if (i > 0) continue; for (s2 = s; /*s2*/; s2 = s2->next) { if (s2->type != NOTEREST) continue; do_combine(s2); if (--r <= 0) break; } continue; } if (s->type != NOTEREST) continue; if (s->abc_type == ABC_T_NOTE) { if (!(s->sflags & S_BEAM_ST)) continue; if (s->sflags & S_BEAM_END) { if (may_combine(s)) do_combine(s); continue; } } else { if (may_combine(s)) do_combine(s); continue; } s2 = s; for (;;) { if (!may_combine(s2)) { s2 = NULL; break; } //fixme: may have rests in beam if (s2->sflags & S_BEAM_END) break; do { s2 = s2->next; } while (s2->type != NOTEREST); } if (!s2) continue; s2 = s; for (;;) { do_combine(s2); //fixme: may have rests in beam if (s2->sflags & S_BEAM_END) break; do { s2 = s2->next; } while (s2->type != NOTEREST); } } } /* -- insert a clef change (treble or bass) before a symbol -- */ static struct SYMBOL *insert_clef(struct SYMBOL *s, int clef_type, int clef_line) { struct VOICE_S *p_voice; struct SYMBOL *new_s; int staff; staff = s->staff; /* don't insert the clef between two bars */ if (s->type == BAR && s->prev && s->prev->type == BAR /* && s->time == s->prev->time */ ) s = s->prev; /* create the symbol */ p_voice = &voice_tb[s->voice]; p_voice->last_sym = s->prev; if (!p_voice->last_sym) p_voice->sym = NULL; p_voice->time = s->time; new_s = sym_add(p_voice, CLEF); new_s->next = s; s->prev = new_s; new_s->u.clef.type = clef_type; new_s->u.clef.line = clef_line; new_s->staff = staff; new_s->aux = 1; /* small clef */ new_s->sflags &= ~S_SECOND; /* link in time */ while (!(s->sflags & S_SEQST)) s = s->ts_prev; // if (!s->ts_prev || s->ts_prev->type != CLEF) if (s->ts_prev->type != CLEF) new_s->sflags |= S_SEQST; new_s->ts_prev = s->ts_prev; // if (new_s->ts_prev) new_s->ts_prev->ts_next = new_s; // else // tsfirst = new_s; new_s->ts_next = s; s->ts_prev = new_s; return new_s; } /* -- set the staff of the floating voices -- */ /* this function is called only once per tune */ static void set_float(void) { struct VOICE_S *p_voice; int staff, staff_chg; struct SYMBOL *s, *s1; for (p_voice = first_voice; p_voice; p_voice = p_voice->next) { if (!p_voice->floating) continue; staff_chg = 0; staff = p_voice->staff; for (s = p_voice->sym; s; s = s->next) { signed char up, down; if (!s->dur) { if (staff_chg) s->staff++; continue; } if (!(s->sflags & S_FLOATING)) { staff_chg = 0; continue; } if (s->pits[0] >= 19) { /* F */ staff_chg = 0; continue; } if (s->pits[s->nhd] <= 12) { /* F, */ staff_chg = 1; s->staff++; continue; } up = 127; for (s1 = s->ts_prev; s1; s1 = s1->ts_prev) { if (s1->staff != staff || s1->voice == s->voice) break; #if 1 /*fixme:test again*/ if (s1->abc_type == ABC_T_NOTE) #endif if (s1->pits[0] < up) up = s1->pits[0]; } if (up == 127) { if (staff_chg) s->staff++; continue; } if (s->pits[s->nhd] > up - 3) { staff_chg = 0; continue; } down = -127; for (s1 = s->ts_next; s1; s1 = s1->ts_next) { if (s1->staff != staff + 1 || s1->voice == s->voice) break; #if 1 /*fixme:test again*/ if (s1->abc_type == ABC_T_NOTE) #endif if (s1->pits[s1->nhd] > down) down = s1->pits[s1->nhd]; } if (down == -127) { if (staff_chg) s->staff++; continue; } if (s->pits[0] < down + 3) { staff_chg = 1; s->staff++; continue; } up -= s->pits[s->nhd]; down = s->pits[0] - down; if (!staff_chg) { if (up < down + 3) continue; staff_chg = 1; } else { if (up < down - 3) { staff_chg = 0; continue; } } s->staff++; } } } /* -- set the x offset of the grace notes -- */ static float set_graceoffs(struct SYMBOL *s) { struct SYMBOL *g, *next; int m; float xx, dx, gspleft, gspinside, gspright; struct note *notes[MAXHD]; gspleft = (cfmt.gracespace >> 16) * 0.1; gspinside = ((cfmt.gracespace >> 8) & 0xff) * 0.1; gspright = (cfmt.gracespace & 0xff) * 0.1; xx = 0; for (g = s->extra; ; g = g->next) { if (g->type == NOTEREST) break; } g->sflags |= S_BEAM_ST; for ( ; ; g = g->next) { if (g->type != NOTEREST) { if (!g->next) break; continue; } set_head_shift(g); for (m = 0; m <= g->nhd; m++) notes[m] = &g->u.note.notes[m]; acc_shift(notes, g->nhd + 1, 7); dx = 0; for (m = g->nhd; m >= 0; m--) { if (g->u.note.notes[m].shac > dx) dx = g->u.note.notes[m].shac; } xx += dx; g->x = xx; if (g->nflags <= 0) g->sflags |= S_BEAM_ST | S_BEAM_END; next = g->next; if (!next) { g->sflags |= S_BEAM_END; break; } if (next->nflags <= 0 || (next->flags & ABC_F_SPACE)) g->sflags |= S_BEAM_END; if (g->sflags & S_BEAM_END) { next->sflags |= S_BEAM_ST; xx += gspinside / 4; } if (g->nflags <= 0) xx += gspinside / 4; if (g->y > next->y + 8) xx -= 1.5; xx += gspinside; } xx += gspleft + gspright; next = s->next; if (next && next->abc_type == ABC_T_NOTE) { /* if before a note */ if (g->y >= 3 * (next->pits[next->nhd] - 18)) xx -= 1; /* above, a bit closer */ else if ((g->sflags & S_BEAM_ST) && g->y < 3 * (next->pits[0] - 18) - 7) xx += 2; /* below with flag, a bit further */ } /* return the whole width */ return xx; } /* -- compute the width needed by the guitar chords / annotations -- */ static float gchord_width(struct SYMBOL *s, float wlnote, float wlw) { struct SYMBOL *s2; struct gch *gch; int ix; float lspc, rspc, w, alspc, arspc; lspc = rspc = alspc = arspc = 0; for (ix = 0, gch = s->gch; ix < MAXGCH; ix++, gch++) { if (gch->type == '\0') break; switch (gch->type) { default: { /* default = above */ float wl; wl = -gch->x; if (wl > lspc) lspc = wl; w = gch->w + 2 - wl; if (w > rspc) rspc = w; break; } case '<': /* left */ w = gch->w + wlnote; if (w > alspc) alspc = w; break; case '>': /* right */ w = gch->w + s->wr; if (w > arspc) arspc = w; break; } } /* adjust width for no clash */ s2 = s->prev; if (s2) { if (s2->gch) { for (s2 = s->ts_prev; ; s2 = s2->ts_prev) { if (s2 == s->prev) { AT_LEAST(wlw, lspc); break; } if (s2->sflags & S_SEQST) lspc -= s2->shrink; } } if (alspc != 0) AT_LEAST(wlw, alspc); } s2 = s->next; if (s2) { if (s2->gch) { for (s2 = s->ts_next; ; s2 = s2->ts_next) { if (s2 == s->next) { AT_LEAST(s->wr, rspc); break; } if (s2->sflags & S_SEQST) rspc -= 8; } } if (arspc != 0) AT_LEAST(s->wr, arspc); } return wlw; } /* -- set the width needed by the lyrics -- */ static float ly_width(struct SYMBOL *s, float wlw) { struct SYMBOL *k; struct lyrics *ly = s->ly; struct lyl *lyl; struct tblt_s *tblt; float align, xx, w; int i; /* check if the lyrics contain tablature definition */ for (i = 0; i < 2; i++) { tblt = voice_tb[s->voice].tblts[i]; if (!tblt) continue; if (tblt->pitch == 0) { /* yes, no width */ for (i = 0; i < MAXLY; i++) { if ((lyl = ly->lyl[i]) == NULL) continue; lyl->s = 0; } return wlw; } } align = 0; for (i = 0; i < MAXLY; i++) { float swfac, shift; char *p; lyl = ly->lyl[i]; if (!lyl) continue; p = lyl->t; w = lyl->w; swfac = lyl->f->swfac; xx = w + 2 * cwid(' ') * swfac; if (s->type == GRACE) { // %%graceword shift = s->wl; } else if ((isdigit((unsigned char) *p) && strlen(p) > 2) || p[1] == ':' || *p == '(' || *p == ')') { float sz; if (*p == '(') { sz = cwid((unsigned char) *p); } else { sz = 0; while (*p != '\0') { /*fixme: KO when '\ooo'*/ if (*p == '\\') { p++; continue; } sz += cwid((unsigned char) *p); if (*p == ' ') break; p++; } } sz *= swfac; shift = (w - sz + 2 * cwid(' ') * swfac) * VOCPRE; if (shift > 20) shift = 20; shift += sz; if (isdigit((unsigned char) lyl->t[0])) { if (shift > align) align = shift; } } else if (*p == LY_HYPH || *p == LY_UNDER) { shift = 0; } else { shift = xx * VOCPRE; if (shift > 20) shift = 20; } lyl->s = shift; AT_LEAST(wlw, shift); xx -= shift; shift = 2 * cwid(' ') * swfac; for (k = s->next; k; k = k->next) { switch (k->type) { case NOTEREST: if (!k->ly || !k->ly->lyl[i]) xx -= 9; else if (k->ly->lyl[i]->t[0] == LY_HYPH || k->ly->lyl[i]->t[0] == LY_UNDER) xx -= shift; else break; if (xx <= 0) break; continue; case CLEF: case TIMESIG: case KEYSIG: xx -= 10; continue; default: xx -= 5; break; } break; } if (xx > s->wr) s->wr = xx; } if (align > 0) { for (i = 0; i < MAXLY; i++) { if ((lyl = ly->lyl[i]) == 0) continue; if (isdigit((unsigned char) lyl->t[0])) lyl->s = align; } } return wlw; } /* -- set the width of a symbol -- */ /* This routine sets the minimal left and right widths wl,wr * so that successive symbols are still separated when * no extra glue is put between them */ static void set_width(struct SYMBOL *s) { struct SYMBOL *s2; int i, m; float xx, w, wlnote, wlw; switch (s->type) { case NOTEREST: /* set the note widths */ s->wr = wlnote = hw_tb[s->head]; /* room for shifted heads and accidental signs */ if (s->xmx > 0) s->wr += s->xmx + 4; s2 = s->prev; if (s2) { switch (s2->type) { case BAR: case CLEF: case KEYSIG: case TIMESIG: wlnote += 3; break; } } for (m = 0; m <= s->nhd; m++) { xx = s->u.note.notes[m].shhd; if (xx < 0) AT_LEAST(wlnote, -xx + 5); if (s->u.note.notes[m].acc) { AT_LEAST(wlnote, s->u.note.notes[m].shac + ((s->u.note.notes[m].acc & 0xf8) ? 6.5 : 4.5)); } } if (s2) { switch (s2->type) { case BAR: case CLEF: case KEYSIG: case TIMESIG: wlnote -= 3; break; } } /* room for the decorations */ if (s->u.note.dc.n != 0) wlnote += deco_width(s); /* space for flag if stem goes up on standalone note */ if ((s->sflags & (S_BEAM_ST | S_BEAM_END)) == (S_BEAM_ST | S_BEAM_END) && s->stem > 0 && s->nflags > 0) AT_LEAST(s->wr, s->xmx + 9); // was 12, then removed, then back again /* leave room for dots and set their offset */ if (s->dots > 0) { switch (s->head) { case H_SQUARE: case H_OVAL: s->xmx += 2; break; case H_EMPTY: s->xmx += 1; break; } AT_LEAST(s->wr, s->xmx + 12); if (s->dots >= 2) s->wr += 3.5 * (s->dots - 1); } /* if a tremolo on 2 notes, have space for the small beam(s) */ if ((s->sflags & (S_TREM2 | S_BEAM_END)) == (S_TREM2 | S_BEAM_END)) AT_LEAST(wlnote, 20); wlw = wlnote; if (s2) { switch (s2->type) { case NOTEREST: /* extra space when up stem - down stem */ if (s2->abc_type == ABC_T_REST) break; if (s2->stem > 0 && s->stem < 0) AT_LEAST(wlw, 7); /* make sure helper lines don't overlap */ if ((s->y > 27 && s2->y > 27) || (s->y < -3 && s2->y < -3)) AT_LEAST(wlw, 6); /* have ties wide enough */ if (s2->sflags & S_TI1) AT_LEAST(wlw, 14); break; case CLEF: /* extra space at start of line */ if ((s2->sflags & S_SECOND) || s2->aux) break; wlw += 8; break; case KEYSIG: /* case TIMESIG: */ wlw += 4; break; } } /* leave room for guitar chord and annotations */ if (s->gch) wlw = gchord_width(s, wlnote, wlw); /* leave room for vocals under note */ /* related to draw_lyrics() */ if (s->ly) wlw = ly_width(s, wlw); /* if preceeded by a grace note sequence, adjust */ if (s2 && s2->type == GRACE) s->wl = wlnote - 4.5; else s->wl = wlw; break; case SPACE: xx = s->u.note.notes[0].shhd * 0.5; s->wr = xx; if (s->gch) xx = gchord_width(s, xx, xx); if (s->u.note.dc.n != 0) xx += deco_width(s); s->wl = xx; break; case BAR: // if (s->sflags & S_NOREPBRA) // break; if (!(s->flags & ABC_F_INVIS)) { int bar_type; bar_type = s->u.bar.type; switch (bar_type) { case B_BAR: w = 5 + 3; break; case (B_BAR << 4) + B_COL: case (B_COL << 4) + B_BAR: w = 5 + 3 + 3 + 5; break; case (B_COL << 4) + B_COL: w = 5 + 5 + 3 + 3 + 3 + 5; break; default: w = 5; for (;;) { switch (bar_type & 0x0f) { case B_OBRA: case B_CBRA: w += 3; break; case B_COL: w += 2; break; } bar_type >>= 4; if (bar_type == 0) break; w += 3; } break; } s->wl = w; if (s->next && s->next->type != TIMESIG) s->wr = 8; else s->wr = 5; // s->shhd[0] = (w - 5) * -0.5; } if (s->u.bar.dc.n != 0) s->wl += deco_width(s); /* have room for the repeat numbers / guitar chord */ if (s->gch && strlen(s->text) < 4) s->wl = gchord_width(s, s->wl, s->wl); break; case CLEF: /* shift the clef to the left - see draw_symbols() */ // if (!(s->flags & ABC_F_INVIS)) { s->wl = 12 + 10; s->wr = (s->aux ? 10 : 12) - 10; // } break; case KEYSIG: { int n1, n2, esp; s->wl = 3; esp = 4; if (s->u.key.nacc == 0) { n1 = s->u.key.sf; /* new key sig */ if (cfmt.cancelkey || n1 == 0) n2 = s->aux; /* old key */ else n2 = 0; if (n1 * n2 >= 0) { /* if no natural */ if (n1 < 0) n1 = -n1; if (n2 < 0) n2 = -n2; if (n2 > n1) n1 = n2; } else { n1 -= n2; if (n1 < 0) n1 = -n1; esp += 3; /* see extra space in draw_keysig() */ } } else { int last_acc; n1 = n2 = s->u.key.nacc; last_acc = s->u.key.accs[0]; for (i = 1; i < n2; i++) { if (s->u.key.pits[i] > s->u.key.pits[i - 1] + 6 || s->u.key.pits[i] < s->u.key.pits[i - 1] - 6) n1--; /* octave */ else if (s->u.key.accs[i] != last_acc) esp += 3; last_acc = s->u.key.accs[i]; } } s->wr = 5.5 * n1 + esp; break; } case TIMESIG: /* !!tied to draw_timesig()!! */ w = 0; for (i = 0; i < s->u.meter.nmeter; i++) { int l; l = sizeof s->u.meter.meter[i].top; if (s->u.meter.meter[i].top[l - 1] == '\0') { l = strlen(s->u.meter.meter[i].top); if (s->u.meter.meter[i].top[1] == '|' || s->u.meter.meter[i].top[1] == '.') l--; /* 'C|' */ } if (s->u.meter.meter[i].bot[0] != '\0') { int l2; l2 = sizeof s->u.meter.meter[i].bot; if (s->u.meter.meter[i].bot[l2 - 1] == '\0') l2 = strlen(s->u.meter.meter[i].bot); if (l2 > l) l = l2; } w += 6.5 * l; } s->wl = w; s->wr = w + 7; break; case MREST: s->wl = 40 / 2 + 16; s->wr = 40 / 2 + 16; break; case GRACE: s->wl = set_graceoffs(s); if (s->ly) ly_width(s, 0); break; case STBRK: if (s->next && s->next->type == CLEF) { s->wr = 2; s->next->aux = 0; /* big clef */ } else { s->wr = 8; } s->wl = s->xmx; break; #if 0 case TEMPO: case PART: case TUPLET: case CUSTOS: #endif case FMTCHG: /* no space */ break; default: bug("Cannot set width for symbol", 1); } } /* -- set the natural space -- */ static float set_space(struct SYMBOL *s) { struct SYMBOL *s2; int i, len, l, stemdir, prev_time; float space; //fixme: s->ts_prev never NULL ? // prev_time = !s->ts_prev ? s->time : s->ts_prev->time; prev_time = s->ts_prev->time; len = s->time - prev_time; /* time skip */ if (len == 0) { switch (s->type) { case MREST: return s->wl + 16; /*fixme:do same thing at start of line*/ case NOTEREST: if (s->ts_prev->type == BAR) { i = 2; if (s->nflags < -2) i = 0; return space_tb[i]; } break; } return 0; } if (s->ts_prev->type == MREST) return s->ts_prev->wr + 16 + 3; // (bar wl=5 wr=8) if (smallest_duration >= MINIM) { if (smallest_duration >= SEMIBREVE) len /= 4; else len /= 2; } if (len >= CROTCHET) { if (len < MINIM) i = 5; else if (len < SEMIBREVE) i = 6; else if (len < BREVE) i = 7; else if (len < BREVE * 2) i = 8; else i = 9; } else { if (len >= QUAVER) i = 4; else if (len >= SEMIQUAVER) i = 3; else if (len >= SEMIQUAVER / 2) i = 2; else if (len >= SEMIQUAVER / 4) i = 1; else i = 0; } l = len - ((SEMIQUAVER / 8) << i); space = space_tb[i]; if (l != 0) { if (l < 0) { space = space_tb[0] * len / (SEMIQUAVER / 8); } else { if (i >= 9) i = 8; space += (space_tb[i + 1] - space_tb[i]) * l / len; } } if (s->dur == 0) { if (s->type == BAR) { if (s->u.bar.type & 0xf0) space *= 0.8; /* complex bar */ else space *= 0.7; } return space; } /* reduce spacing within a beam */ if (!(s->sflags & S_BEAM_ST)) space *= fnnp; /* decrease spacing when stem down followed by stem up */ /*fixme:to be done later, after x computed in sym_glue*/ if (s->abc_type == ABC_T_NOTE && s->nflags >= -1 && s->stem > 0) { stemdir = 1; for (s2 = s->ts_prev; s2 && s2->time == prev_time; s2 = s2->ts_prev) { if (s2->nflags < -1 || s2->stem > 0) { stemdir = 0; break; } } if (stemdir) { for (s2 = s->ts_next; s2 && s2->time == s->time; s2 = s2->ts_next) { if (s2->nflags < -1 || s2->stem < 0) { stemdir = 0; break; } } if (stemdir) space *= 0.9; } } return space; } /* -- set the width and space of all symbols -- */ /* this function is called once for the whole tune * then, once per music line up to the first sequence */ static void set_allsymwidth(struct SYMBOL *last_s) { #if 1 // float space; float new_val, maxx; struct SYMBOL *s = tsfirst, *s2; float xa = 0; float xl[MAXSTAFF]; memset(xl, 0, sizeof xl); /* loop on all symbols */ while (1) { maxx = xa; s2 = s; // space = 0; do { set_width(s); new_val = xl[s->staff] + s->wl; if (new_val > maxx) maxx = new_val; // if (s->ts_prev) { // new_val = set_space(s); // if (space < new_val) // space = new_val; // } s = s->ts_next; } while (s != last_s && (s->sflags & S_SEQST) == 0); /* set the spaces at start of sequence */ s2->shrink = maxx - xa; if (s2->ts_prev) s2->space = set_space(s2); if (s2->shrink == 0 && s2->space == 0 && s2->type == CLEF) { s2->sflags &= ~S_SEQST; /* no space */ s2->time = s2->ts_prev->time; } if (s == last_s) return; // update the min left space per staff xa = maxx; s = s2; do { if (xl[s->staff] < xa + s->wr) xl[s->staff] = xa + s->wr; s = s->ts_next; } while ((s->sflags & S_SEQST) == 0); } // not reached #else struct VOICE_S *p_voice; struct SYMBOL *s, *s2, *s3; struct tblt_s *tblt; int i; float new_val, shrink, space; /* set the space of the starting symbols */ new_val = 0; s = tsfirst; for (;;) { set_width(s); if (new_val < s->wl) new_val = s->wl; s = s->ts_next; if (s == last_s || (s->sflags & S_SEQST)) break; } tsfirst->shrink = new_val; /* loop on all remaining symbols */ while (s != last_s) { s2 = s; shrink = space = 0; do { int ymx1, ymn1, ymx2, ymn2; float wl; /* set the minimum space before and after the symbol */ set_width(s2); /* calculate the minimum space before the symbol, * looping in the previous time sequence */ if (s2->type == BAR) { ymx1 = 50; ymn1 = -50; } else { ymx1 = s2->ymx; ymn1 = s2->ymn; } wl = s2->wl; new_val = 0; for (s3 = s->ts_prev; s3; s3 = s3->ts_prev) { if (new_val < s3->wr && s3->type == NOTEREST && s2->type == NOTEREST) new_val = s3->wr; if (s3->staff == s2->staff && (!(s3->flags & ABC_F_INVIS) || s3->voice == s2->voice) && new_val < s3->wr + wl) { switch (s3->type) { case NOTEREST: if (s2->type == NOTEREST) { new_val = s3->wr + wl; break; } /* fall thru */ default: ymx2 = s3->ymx; ymn2 = s3->ymn; if (ymn1 > ymx2 || ymx1 < ymn2) break; /* fall thru */ case SPACE: case BAR: case CLEF: case TIMESIG: case KEYSIG: new_val = s3->wr + wl; break; } } if (s3->sflags & S_SEQST) { if (new_val != 0) break; wl -= s3->shrink; if (wl < 0) break; } } if (shrink < new_val) shrink = new_val; new_val = set_space(s2); if (space < new_val) space = new_val; if ((s2 = s2->ts_next) == last_s) break; } while (!(s2->sflags & S_SEQST)); /* set the spaces at start of sequence */ if (shrink == 0 && space == 0 && s->type == CLEF) { s->sflags &= ~S_SEQST; /* no space */ s->time = s->ts_prev->time; } else { s->shrink = shrink; s->space = space; } s = s2; } /* have room for the tablature header */ space = 0; for (p_voice = first_voice; p_voice; p_voice = p_voice->next) { for (i = 0; i < 2; i++) { if ((tblt = p_voice->tblts[i]) == NULL) continue; if (tblt->wh > space) space = tblt->wh; } } if (space == 0) return; shrink = 0; for (s = tsfirst; s != last_s; s = s->ts_next) { if (s->shrink != 0) shrink += s->shrink; if (s->abc_type == ABC_T_NOTE) break; } if (s != last_s && shrink < space) { while (!(s->sflags & S_SEQST)) s = s->ts_prev; s->shrink += space - shrink; } #endif } /* change a symbol into a rest */ static void to_rest(struct SYMBOL *s) { s->type = NOTEREST; s->abc_type = ABC_T_REST; s->sflags &= S_NL | S_SEQST; s->doty = -1; s->u.note.dc.n = 0; s->gch = NULL; s->extra = NULL; s->u.note.slur_st = s->u.note.slur_end = 0; /*fixme: should set many parameters for set_width*/ // set_width(s); } /* -- set the repeat sequences / measures -- */ static void set_repeat(struct SYMBOL *g, /* repeat format */ struct SYMBOL *s) /* first note */ { struct SYMBOL *s2, *s3; int i, j, n, dur, staff, voice; staff = s->staff; voice = s->voice; /* treat the sequence repeat */ if ((n = g->doty) < 0) { /* number of notes / measures */ n = -n; i = n; /* number of notes to repeat */ for (s3 = s->prev; s3; s3 = s3->prev) { if (s3->dur == 0) { if (s3->type == BAR) { error(0, s3, "Bar in sequence to repeat"); goto delrep; } continue; } if (--i <= 0) break; } if (!s3) { error(0, s, "Not enough symbols to repeat"); goto delrep; } dur = s->time - s3->time; i = g->nohdi1 * n; /* number of notes/rests to repeat */ for (s2 = s; s2; s2 = s2->next) { if (s2->dur == 0) { if (s2->type == BAR) { error(0, s2, "Bar in repeat sequence"); goto delrep; } continue; } if (--i <= 0) break; } if (!s2 || !s2->next) { /* should have some symbol */ error(0, s, "Not enough symbols after repeat sequence"); goto delrep; } for (s2 = s->prev; s2 != s3; s2 = s2->prev) { if (s2->abc_type == ABC_T_NOTE) { s2->sflags |= S_BEAM_END; break; } } for (j = g->nohdi1; --j >= 0; ) { i = n; /* number of notes/rests */ if (s->dur != 0) i--; s2 = s->ts_next; while (i > 0) { if (s2->staff == staff) { s2->extra = NULL; unlksym(s2); if (s2->voice == voice && s2->dur) i--; } s2 = s2->ts_next; } to_rest(s); s->dur = s->u.note.notes[0].len = dur; // s->sflags |= S_REPEAT | S_BEAM_ST; s->sflags |= S_REPEAT; set_width(s); if (s->sflags & S_SEQST) s->space = set_space(s); s->head = H_SQUARE; for (s = s2; s; s = s->ts_next) { if (s->staff == staff && s->voice == voice && s->dur) break; } } goto delrep; /* done */ } /* check the measure repeat */ i = n; /* number of measures to repeat */ for (s2 = s->prev->prev ; s2; s2 = s2->prev) { if (s2->type == BAR || s2->time == tsfirst->time) { if (--i <= 0) break; } } if (!s2) { error(0, s, "Not enough measures to repeat"); goto delrep; } dur = s->time - s2->time; /* repeat duration */ if (n == 1) i = g->nohdi1; /* repeat number */ else i = n; /* check only 2 measures */ for (s2 = s; s2; s2 = s2->next) { if (s2->type == BAR) { if (--i <= 0) break; } } if (!s2) { error(0, s, "Not enough bars after repeat measure"); goto delrep; } /* if many 'repeat 2 measures' * insert a new %%repeat after the next bar */ i = g->nohdi1; /* repeat number */ if (n == 2 && i > 1) { s2 = s2->next; if (!s2) { error(0, s, "Not enough bars after repeat measure"); goto delrep; } g->nohdi1 = 1; s = (struct SYMBOL *) getarena(sizeof *s); memcpy(s, g, sizeof *s); s->next = s2->extra; if (s->next) s->next->prev = s; s->prev = NULL; s2->extra = s; s->nohdi1 = --i; } /* replace */ dur /= n; if (n == 2) { /* repeat 2 measures (once) */ s3 = s; for (s2 = s->ts_next; ;s2 = s2->ts_next) { if (s2->staff != staff) continue; if (s2->voice == voice && s2->type == BAR) break; s2->extra = NULL; unlksym(s2); } to_rest(s3); s3->dur = s3->u.note.notes[0].len = dur; s3->flags = ABC_F_INVIS; if (s3->sflags & S_SEQST) s3->space = set_space(s3); s2->u.bar.len = 2; if (s2->sflags & S_SEQST) s2->space = set_space(s2); s3 = s2->next; for (s2 = s3->ts_next; ;s2 = s2->ts_next) { if (s2->staff != staff) continue; if (s2->voice == voice && s2->type == BAR) break; s2->extra = NULL; unlksym(s2); } to_rest(s3); s3->dur = s3->u.note.notes[0].len = dur; s3->flags = ABC_F_INVIS; set_width(s3); if (s3->sflags & S_SEQST) s3->space = set_space(s3); if (s2->sflags & S_SEQST) s2->space = set_space(s2); return; } /* repeat 1 measure */ s3 = s; for (j = g->nohdi1; --j >= 0; ) { for (s2 = s3->ts_next; ; s2 = s2->ts_next) { if (s2->staff != staff) continue; if (s2->voice == voice && s2->type == BAR) break; s2->extra = NULL; unlksym(s2); } to_rest(s3); s3->dur = s3->u.note.notes[0].len = dur; // s3->sflags |= S_REPEAT | S_BEAM_ST; s3->sflags |= S_REPEAT; if (s3->sflags & S_SEQST) s3->space = set_space(s3); if (s2->sflags & S_SEQST) s2->space = set_space(s2); if (g->nohdi1 == 1) { s3->doty = 1; break; } s3->doty = g->nohdi1 - j + 1; /* number to print above the repeat rest */ s3 = s2->next; } return; delrep: /* remove the %%repeat */ g->aux = -1; } /* add a custos before the symbol of the next line */ static void custos_add(struct SYMBOL *s) { struct VOICE_S *p_voice; struct SYMBOL *new_s, *s2; int i; s2 = s; for (;;) { if (!s2) return; if (s2->abc_type == ABC_T_NOTE) break; s2 = s2->next; } p_voice = &voice_tb[s->voice]; p_voice->last_sym = s->prev; if (!p_voice->last_sym) p_voice->sym = NULL; p_voice->time = s->time; new_s = sym_add(p_voice, CUSTOS); new_s->next = s; s->prev = new_s; new_s->ts_prev = s->ts_prev; new_s->ts_prev->ts_next = new_s; new_s->ts_next = s; s->ts_prev = new_s; new_s->sflags |= S_SEQST; new_s->wl = 8; new_s->wr = 4; new_s->shrink = s->shrink; if (new_s->shrink < 8 + 4) new_s->shrink = 8 + 4; new_s->space = s2->space; new_s->nhd = s2->nhd; for (i = 0; i <= new_s->nhd; i++) { // new_s->u.note.notes[i].pit = s->u.note.notes[i].pit; new_s->pits[i] = s2->pits[i]; new_s->u.note.notes[i].len = CROTCHET; } new_s->flags = ABC_F_STEMLESS; } /* -- define the beginning of a new music line -- */ static struct SYMBOL *set_nl(struct SYMBOL *s) { struct SYMBOL *s2, *extra, *new_sy; struct VOICE_S *p_voice; int done; /* if explicit EOLN, cut on the next symbol */ if ((s->sflags & S_EOLN) && !cfmt.keywarn && !cfmt.timewarn) { s = s->next; if (!s) return s; while (!(s->sflags & S_SEQST)) s = s->ts_prev; goto setnl; } /* if normal symbol, cut here */ switch (s->type) { case CLEF: case BAR: break; case KEYSIG: if (cfmt.keywarn && !s->u.key.empty) break; goto normal; case TIMESIG: if (cfmt.timewarn) break; goto normal; case GRACE: /* don't cut on a grace note */ s = s->next; if (!s) return s; /* fall thru */ default: normal: /* cut on the next symbol */ s = s->next; if (!s) return s; while (!(s->sflags & S_SEQST)) s = s->ts_prev; goto setnl; } /* go back to handle the staff breaks at end of line */ for (; s; s = s->ts_prev) { if (!(s->sflags & S_SEQST)) continue; switch (s->type) { case CLEF: case KEYSIG: case TIMESIG: continue; } break; } done = 0; new_sy = extra = NULL; for ( ; ; s = s->ts_next) { if (!s) return s; if (s->sflags & S_NEW_SY) new_sy = s; if (!(s->sflags & S_SEQST)) continue; if (done < 0) break; switch (s->type) { case BAR: if (done) goto cut_here; done = 1; break; case STBRK: if (s->doty == 0) { /* if not forced */ unlksym(s); /* remove */ break; } done = -1; /* keep the next symbols on the next line */ break; case TIMESIG: if (!cfmt.timewarn) goto cut_here; break; case CLEF: if (done) goto cut_here; break; case KEYSIG: if (!cfmt.keywarn || s->u.key.empty) goto cut_here; break; default: if (!done || (s->prev && s->prev->type == GRACE)) break; goto cut_here; } if (s->extra) { if (!extra) extra = s; else error(0, s, "abcm2ps problem: " "Extra symbol may be misplaced"); } } cut_here: if (extra /* extra symbol(s) to be moved */ && extra != s) { s2 = extra->extra; while (s2->next) s2 = s2->next; s2->next = s->extra; s->extra = extra->extra; extra->extra = NULL; } if (new_sy && s != new_sy) { new_sy->sflags &= ~S_NEW_SY; s->sflags |= S_NEW_SY; } setnl: if (cfmt.custos && !first_voice->next) { custos_add(s); } else { s2 = s->ts_prev; switch (s2->type) { case BAR: case FMTCHG: case CLEF: case KEYSIG: case TIMESIG: break; default: /* add an extra symbol at eol */ p_voice = &voice_tb[s2->voice]; p_voice->last_sym = s2; p_voice->time = s->time; s2 = s2->next; extra = sym_add(p_voice, FMTCHG); extra->next = s2; if (s2) s2->prev = extra; extra->ts_prev = extra->prev; extra->ts_prev->ts_next = extra; extra->ts_next = s; s->ts_prev = extra; extra->aux = -1; extra->sflags |= S_SEQST; extra->wl = 6; //fixme: wr/shrink/space are not needed extra->wr = 6; // extra->shrink = extra->prev->wr + 6; // extra->space = extra->prev->space; extra->shrink = s->shrink; extra->space = s->space; if (s->x != 0) extra->x = s->x - 1; // { /* auto break */ // for (s2 = s->ts_next; ; s2 = s2->ts_next) { // if (s2->x != 0) { // extra->x = s2->x - 1; // break; // } // } // } break; } } s->sflags |= S_NL; return s; } /* -- search where to cut the lines according to the staff width -- */ static struct SYMBOL *set_lines(struct SYMBOL *first, /* first symbol */ struct SYMBOL *last, /* last symbol / 0 */ float lwidth, /* w - (clef & key sig) */ float indent) /* for start of tune */ { struct SYMBOL *s, *s2, *s3; float x, xmin, xmax, wwidth, shrink, space; int nlines, beam, bar_time; /* calculate the whole size of the piece of tune */ wwidth = indent; for (s = first; s != last; s = s->ts_next) { if (!(s->sflags & S_SEQST)) continue; s->x = wwidth; shrink = s->shrink; if ((space = s->space) < shrink) wwidth += shrink; else wwidth += shrink * cfmt.maxshrink + space * (1 - cfmt.maxshrink); } /* loop on cutting the tune into music lines */ s = first; for (;;) { nlines = wwidth / lwidth + 0.999; if (nlines <= 1) { if (last) last = set_nl(last); return last; } /* try to cut on a measure bar */ s2 = first = s; xmin = s->x + wwidth / nlines * cfmt.breaklimit; xmax = s->x + lwidth; for ( ; s != last; s = s->ts_next) { x = s->x; if (x == 0) continue; if (x > xmax) break; if (s->type != BAR) continue; if (x > xmin) goto cut_here; s2 = s; // keep the last bar } /* if a bar, cut here */ if (s == last) return last; if (s->type == BAR) goto cut_here; bar_time = s2->time; /* try to avoid to cut a beam */ beam = s2->type == NOTEREST && (s2->sflags & (S_BEAM_ST | S_BEAM_END)) == 0 ? 1 : 0; s = s2; /* restart from start or last bar */ s2 = s3 = NULL; xmax -= 6; // a FORMAT will be added for ( ; s != last; s = s->ts_next) { if ((s->sflags & (S_BEAM_ST | S_BEAM_END)) == S_BEAM_ST) { beam++; continue; } if ((s->sflags & (S_BEAM_ST | S_BEAM_END)) == S_BEAM_END) beam--; x = s->x; if (x < xmin) continue; //--fixme // if (x + 2 * s->shrink >= xmax) if (x + s->shrink >= xmax) break; if (beam != 0) continue; s2 = s; if ((s->time - bar_time) % (CROTCHET / 2) == 0) s3 = s; } if (s3) s2 = s3; if (s2) s = s2; while (s->x == 0 || s->x + s->shrink * 2 >= xmax) s = s->ts_prev; cut_here: if (s->sflags & S_NL) { /* already set here - advance */ error(0, s, "Line split problem - " "adjust maxshrink and/or breaklimit"); nlines = 2; for (s = s->ts_next; s != last; s = s->ts_next) { if (s->x == 0) continue; if (--nlines <= 0) break; } } s = set_nl(s); if (!s || (last && s->time >= last->time)) break; wwidth -= s->x - first->x; } return s; } /* -- cut the tune into music lines -- */ static void cut_tune(float lwidth, float indent) { struct VOICE_S *p_voice; struct SYMBOL *s, *s2; int i; float xmin; /* adjust the line width according to the starting clef * and key signature */ /*fixme: may change in the tune*/ #if 1 s = tsfirst; for (p_voice = first_voice; p_voice; p_voice = p_voice->next) { i = p_voice - voice_tb; if (cursys->voice[i].range >= 0) break; } lwidth -= 12 + 10 // clef.wl + 12 - 10 // clef.wr + 3 // key.wl + 3 + p_voice->key.sf * 5.5; // key.wr #else for (s = tsfirst; s; s = s->ts_next) { if (s->shrink == 0) continue; if (s->type != CLEF && s->type != KEYSIG) break; lwidth -= s->shrink; } #endif if (cfmt.custos && !first_voice->next) lwidth -= 12; if (cfmt.continueall) { set_lines(s, NULL, lwidth, indent); return; } /* if asked, count the measures and set the EOLNs */ if ((i = cfmt.barsperstaff) != 0) { s2 = s; for ( ; s; s = s->ts_next) { if (s->type != BAR || s->aux == 0) continue; if (--i > 0) continue; s->sflags |= S_EOLN; i = cfmt.barsperstaff; } s = s2; } /* cut at explicit end of line, checking the line width */ xmin = indent; s2 = s; for ( ; s; s = s->ts_next) { if (!(s->sflags & (S_SEQST | S_EOLN))) continue; xmin += s->shrink; if (xmin > lwidth) { if (cfmt.linewarn) error(0, s, "Line overfull (%.0fpt of %.0fpt)", xmin, lwidth); // for (s = s->ts_next; s; s = s->ts_next) { for ( ; s; s = s->ts_next) { if (s->sflags & S_EOLN) break; } s = s2 = set_lines(s2, s, lwidth, indent); if (!s) break; xmin = s->shrink; indent = 0; continue; } if (!(s->sflags & S_EOLN)) continue; s2 = set_nl(s); s->sflags &= ~S_EOLN; s = s2; if (!s) break; xmin = s->shrink; indent = 0; } } /* -- set the y values of some symbols -- */ static void set_yval(struct SYMBOL *s) { //fixme: staff_tb is not yet loaded // int top, bot; // top = staff_tb[s->staff].topbar; // bot = staff_tb[s->staff].botbar; switch (s->type) { case CLEF: if ((s->sflags & S_SECOND) || (s->flags & ABC_F_INVIS)) { // s->ymx = s->ymn = (top + bot) / 2; s->ymx = s->ymn = 12; break; } s->y = (s->u.clef.line - 1) * 6; switch (s->u.clef.type) { default: /* treble / perc */ // s->y = -2 * 6; // s->ymx = 24 + 12; // s->ymn = -9; s->ymx = s->y + 28; s->ymn = s->y - 14; break; case ALTO: // s->y = -3 * 6; // s->ymx = 24 + 2; // s->ymn = -1; s->ymx = s->y + 13; s->ymn = s->y - 11; break; case BASS: // s->y = -4 * 6; // s->ymx = 24 + 2; // s->ymn = 2; s->ymx = s->y + 7; s->ymn = s->y - 12; break; } if (s->aux) { // small clef s->ymx -= 2; s->ymn += 2; } if (s->ymx < 26) s->ymx = 26; if (s->ymn > -1) s->ymn = -1; // s->y += s->u.clef.line * 6; // if (s->y > 0) // s->ymx += s->y; // else if (s->y < 0) // s->ymn += s->y; if (s->u.clef.octave > 0) s->ymx += 9; else if (s->u.clef.octave < 0) s->ymn -= 9; break; case KEYSIG: if (s->u.key.sf > 2) s->ymx = 24 + 10; else if (s->u.key.sf > 0) s->ymx = 24 + 6; else s->ymx = 24 + 2; s->ymn = -2; break; default: // s->ymx = top + 2; s->ymx = 24 + 2; s->ymn = -2; break; } } // set the clefs (treble or bass) in a 'auto clef' sequence // return the starting clef type static int set_auto_clef(int staff, struct SYMBOL *s_start, int clef_type_start) { struct SYMBOL *s; struct SYMBOL *s_last, *s_last_chg; int clef_type, min, max, time; /* get the max and min pitches in the sequence */ max = 12; /* "F," */ min = 20; /* "G" */ for (s = s_start; s; s = s->ts_next) { if ((s->sflags & S_NEW_SY) && s != s_start) break; if (s->staff != staff) continue; if (s->abc_type != ABC_T_NOTE) { if (s->type == CLEF) { if (s->u.clef.type != AUTOCLEF) break; unlksym(s); } continue; } if (s->pits[0] < min) min = s->pits[0]; else if (s->pits[s->nhd] > max) max = s->pits[s->nhd]; } if (min >= 19 /* upper than 'F' */ || (min >= 13 && clef_type_start != BASS)) /* or 'G,' */ return TREBLE; if (max <= 13 /* lower than 'G,' */ || (max <= 19 && clef_type_start != TREBLE)) /* or 'F' */ return BASS; /* set clef changes */ if (clef_type_start == AUTOCLEF) { if ((max + min) / 2 >= 16) clef_type_start = TREBLE; else clef_type_start = BASS; } clef_type = clef_type_start; s_last = s; s_last_chg = NULL; for (s = s_start; s != s_last; s = s->ts_next) { struct SYMBOL *s2, *s3; //, *s4; if ((s->sflags & S_NEW_SY) && s != s_start) break; if (s->staff != staff || s->abc_type != ABC_T_NOTE) continue; /* check if a clef change may occur */ time = s->time; if (clef_type == TREBLE) { if (s->pits[0] > 12 /* F, */ || s->pits[s->nhd] > 20) { /* G */ if (s->pits[0] > 20) s_last_chg = s; continue; } s2 = s->ts_prev; if (s2 && s2->time == time && s2->staff == staff && s2->abc_type == ABC_T_NOTE && s2->pits[0] >= 19) /* F */ continue; s2 = s->ts_next; if (s2 && s2->staff == staff && s2->time == time && s2->abc_type == ABC_T_NOTE && s2->pits[0] >= 19) /* F */ continue; } else { if (s->pits[0] < 12 /* F, */ || s->pits[s->nhd] < 20) { /* G */ if (s->pits[s->nhd] < 12) s_last_chg = s; continue; } s2 = s->ts_prev; if (s2 && s2->time == time && s2->staff == staff && s2->abc_type == ABC_T_NOTE && s2->pits[0] <= 13) /* G, */ continue; s2 = s->ts_next; if (s2 && s2->staff == staff && s2->time == time && s2->abc_type == ABC_T_NOTE && s2->pits[0] <= 13) /* G, */ continue; } /* if first change, change the starting clef */ if (!s_last_chg) { clef_type = clef_type_start = clef_type == TREBLE ? BASS : TREBLE; s_last_chg = s; continue; } /* go backwards and search where to insert a clef change */ s3 = s; for (s2 = s->ts_prev; s2 != s_last_chg; s2 = s2->ts_prev) { if (s2->staff != staff) continue; if (s2->type == BAR && s2->voice == s->voice) { s3 = s2; break; } if (s2->abc_type != ABC_T_NOTE) continue; #if 0 /* exit loop if a clef change cannot occur */ if (clef_type == TREBLE) { if (s2->pits[0] >= 19) /* F */ break; } else { if (s2->pits[s2->nhd] <= 13) /* G, */ break; } #endif /* have a 2nd choice on beam start */ if ((s2->sflags & S_BEAM_ST) && !voice_tb[s2->voice].second) s3 = s2; } /* no change possible if no insert point */ if (s3->time == s_last_chg->time) { s_last_chg = s; continue; } s_last_chg = s; /* insert a clef change */ clef_type = clef_type == TREBLE ? BASS : TREBLE; s2 = insert_clef(s3, clef_type, clef_type == TREBLE ? 2 : 4); s2->sflags |= S_CLEF_AUTO; // s3->prev->staff = staff; } return clef_type_start; } /* set the auto clefs */ /* this function is called once at start of tune generation */ /* * global variables: * - staff_tb[staff].clef = clefs at start of line (here, start of tune) * (created here, updated on clef draw) * - voice_tb[voice].clef = clefs at end of generation * (created on voice creation, updated here) */ static void set_clefs(void) { struct SYSTEM *sy; struct VOICE_S *p_voice; struct SYMBOL *s, *s2, *g; int staff, voice, pitch, new_type, new_line, old_lvl; struct { struct SYMBOL *clef; short autoclef; short mid; } staff_clef[MAXSTAFF]; old_lvl = lvlarena(1); // keep the staff clefs // create the staff table memset(staff_tb, 0, sizeof staff_tb); for (staff = 0; staff <= nstaff; staff++) { staff_clef[staff].clef = NULL; staff_clef[staff].autoclef = 1; } // set the starting clefs of the staves sy = cursys; for (p_voice = first_voice; p_voice; p_voice = p_voice->next) { voice = p_voice - voice_tb; if (sy->voice[voice].range < 0) continue; staff = sy->voice[voice].staff; if (!sy->voice[voice].second) { // main voices if (p_voice->stafflines) sy->staff[staff].stafflines = p_voice->stafflines; if (p_voice->staffscale != 0) sy->staff[staff].staffscale = p_voice->staffscale; if (sy->voice[voice].sep) sy->staff[staff].sep = sy->voice[voice].sep; if (sy->voice[voice].maxsep) sy->staff[staff].maxsep = sy->voice[voice].maxsep; } s = p_voice->s_clef; if (!sy->voice[voice].second && !(s->sflags & S_CLEF_AUTO)) staff_clef[staff].autoclef = 0; } for (p_voice = first_voice; p_voice; p_voice = p_voice->next) { voice = p_voice - voice_tb; if (sy->voice[voice].range < 0 || sy->voice[voice].second) // main voices continue; staff = sy->voice[voice].staff; s = p_voice->s_clef; if (staff_clef[staff].autoclef) { s->u.clef.type = set_auto_clef(staff, tsfirst, s->u.clef.type); s->u.clef.line = s->u.clef.type == TREBLE ? 2 : 4; } staff_clef[staff].clef = staff_tb[staff].s_clef = s; } for (staff = 0; staff <= sy->nstaff; staff++) staff_clef[staff].mid = (strlen(sy->staff[staff].stafflines) - 1) * 3; for (s = tsfirst; s; s = s->ts_next) { for (g = s->extra ; g; g = g->next) { if (g->type == FMTCHG && g->aux == REPEAT) { set_repeat(g, s); break; } } // handle %%staves if (s->sflags & S_NEW_SY) { sy = sy->next; for (staff = 0; staff <= nstaff; staff++) staff_clef[staff].autoclef = 1; for (p_voice = first_voice; p_voice; p_voice = p_voice->next) { voice = p_voice - voice_tb; if (sy->voice[voice].range < 0) continue; staff = sy->voice[voice].staff; if (!sy->voice[voice].second) { if (p_voice->stafflines) sy->staff[staff].stafflines = p_voice->stafflines; if (p_voice->staffscale != 0) sy->staff[staff].staffscale = p_voice->staffscale; if (sy->voice[voice].sep) sy->staff[staff].sep = sy->voice[voice].sep; if (sy->voice[voice].maxsep) sy->staff[staff].maxsep = sy->voice[voice].maxsep; } s2 = p_voice->s_clef; if (!(s2->sflags & S_CLEF_AUTO)) staff_clef[staff].autoclef = 0; } for (staff = 0; staff <= sy->nstaff; staff++) staff_clef[staff].mid = (strlen(sy->staff[staff].stafflines) - 1) * 3; for (p_voice = first_voice; p_voice; p_voice = p_voice->next) { voice = p_voice - voice_tb; if (sy->voice[voice].range < 0 || sy->voice[voice].second) continue; staff = sy->voice[voice].staff; s2 = p_voice->s_clef; if (s2->sflags & S_CLEF_AUTO) { //fixme: the staff may have other voices with explicit clefs... // if (!staff_clef[staff].autoclef) // ??? new_type = set_auto_clef(staff, s, staff_clef[staff].clef ? staff_clef[staff].clef->u.clef.type : AUTOCLEF); new_line = new_type == TREBLE ? 2 : 4; } else { new_type = s2->u.clef.type; new_line = s2->u.clef.line; } if (!staff_clef[staff].clef) { // new staff if (s2->sflags & S_CLEF_AUTO) { if (s2->u.clef.type != AUTOCLEF) { p_voice->s_clef = (struct SYMBOL *) getarena(sizeof *s); memcpy(p_voice->s_clef, s2, sizeof *p_voice->s_clef); } p_voice->s_clef->u.clef.type = new_type; p_voice->s_clef->u.clef.line = new_line; } staff_tb[staff].s_clef = staff_clef[staff].clef = p_voice->s_clef; continue; } // old staff if (new_type == staff_clef[staff].clef->u.clef.type && new_line == staff_clef[staff].clef->u.clef.line) continue; g = s; while (g && g->voice != voice) g = g->ts_next; if (!g) continue; if (g->type != CLEF) { g = insert_clef(g, new_type, new_line); if (s2->sflags & S_CLEF_AUTO) g->sflags |= S_CLEF_AUTO; } staff_clef[staff].clef = p_voice->s_clef = g; } } if (s->type != CLEF) { s->mid = staff_clef[s->staff].mid; continue; } if (s->u.clef.type == AUTOCLEF) { s->u.clef.type = set_auto_clef(s->staff, s->ts_next, staff_clef[s->staff].clef->u.clef.type); s->u.clef.line = s->u.clef.type == TREBLE ? 2 : 4; } p_voice = &voice_tb[s->voice]; p_voice->s_clef = s; if (s->sflags & S_SECOND) { /*fixme:%%staves:can this happen?*/ // if (!s->prev) // break; unlksym(s); continue; } staff = s->staff; // may have been inserted on %%staves // if (s->sflags & S_CLEF_AUTO) { // unlksym(s); // continue; // } if (staff_tb[staff].s_clef) { if (s->u.clef.type == staff_clef[staff].clef->u.clef.type && s->u.clef.line == staff_clef[staff].clef->u.clef.line && !(s->sflags & S_NEW_SY)) { // unlksym(s); continue; } } else { // the voice moved to a new staff with a forced clef staff_tb[staff].s_clef = s; } staff_clef[staff].clef = s; } /* set a pitch to the symbols of voices with no note */ sy = cursys; for (p_voice = first_voice; p_voice; p_voice = p_voice->next) { voice = p_voice - voice_tb; if (sy->voice[voice].range < 0) continue; s2 = p_voice->sym; if (!s2 || s2->pits[0] != 127) continue; staff = sy->voice[voice].staff; switch (staff_tb[staff].s_clef->u.clef.type) { default: pitch = 22; /* 'B' */ break; case ALTO: pitch = 16; /* 'C' */ break; case BASS: pitch = 10; /* 'D,' */ break; } for (s = s2; s; s = s->next) s->pits[0] = pitch; } lvlarena(old_lvl); } /* -- set the pitch of the notes according to the clefs -- */ /* also treat the auto clefs and set the vertical offset of the symbols */ /* this function is called only once per tune * then, once per music line up to the old sequence */ static void set_pitch(struct SYMBOL *last_s) { struct SYMBOL *s, *g; int staff, delta, dur; signed char staff_delta[MAXSTAFF]; static const signed char delta_tb[4] = { 0 - 2 * 2, 6 - 3 * 2, 12 - 4 * 2, 0 - 3 * 2 }; for (staff = 0; staff <= nstaff; staff++) { s = staff_tb[staff].s_clef; staff_delta[staff] = delta_tb[s->u.clef.type] + s->u.clef.line * 2 + s->u.clef.transpose; } dur = BASE_LEN; for (s = tsfirst; s != last_s; s = s->ts_next) { int np, m; staff = s->staff; switch (s->type) { case CLEF: staff_delta[staff] = delta_tb[s->u.clef.type] + s->u.clef.line * 2 + s->u.clef.transpose; set_yval(s); break; case GRACE: for (g = s->extra; g; g = g->next) { if (g->type != NOTEREST) continue; delta = staff_delta[g->staff]; if (delta != 0 && voice_tb[s->voice].key.instr != K_DRUM) { for (m = g->nhd; m >= 0; m--) g->pits[m] += delta; } g->ymn = 3 * (g->pits[0] - 18) - 2; g->ymx = 3 * (g->pits[g->nhd] - 18) + 2; } set_yval(s); break; case KEYSIG: s->u.key.clef_delta = staff_delta[staff]; /* keep the current clef */ // s->ymx = 24 + 10; // s->ymn = -2; // break; /* fall thru */ default: set_yval(s); break; case MREST: if (s->flags & ABC_F_INVIS) break; s->ymx = 24 + 15; s->ymn = -2; break; case NOTEREST: if (s->abc_type != ABC_T_NOTE && !first_voice->next) { s->y = 12; /* rest single voice */ s->ymx = 24; s->ymn = 0; break; } np = s->nhd; delta = staff_delta[staff]; if (delta != 0 && voice_tb[s->voice].key.instr != K_DRUM) { for (m = np; m >= 0; m--) s->pits[m] += delta; } if (s->abc_type == ABC_T_NOTE) { s->ymx = 3 * (s->pits[np] - 18) + 4; s->ymn = 3 * (s->pits[0] - 18) - 4; } else { s->y = (s->pits[0] - 18) / 2 * 6; s->ymx = s->y + rest_sp[5 - s->nflags][0]; s->ymn = s->y - rest_sp[5 - s->nflags][1]; } if (s->dur < dur) dur = s->dur; break; } } smallest_duration = dur; } /* -- set the stem direction when multi-voices -- */ /* this function is called only once per tune */ static void set_stem_dir(void) { struct SYSTEM *sy; struct SYMBOL *s, *t, *u; int i, staff, nst, rvoice, voice; struct { int nvoice; struct { int voice; short ymn; short ymx; } st[4]; /* (no more than 4 voices per staff) */ } stb[MAXSTAFF]; struct { signed char st1, st2; /* (a voice cannot be on more than 2 staves) */ } vtb[MAXVOICE]; s = tsfirst; sy = cursys; nst = sy->nstaff; while (s) { for (staff = nst; staff >= 0; staff--) { stb[staff].nvoice = -1; for (i = 4; --i >= 0; ) { stb[staff].st[i].voice = -1; stb[staff].st[i].ymx = 0; stb[staff].st[i].ymn = 24; } } for (i = 0; i < MAXVOICE; i++) vtb[i].st1 = vtb[i].st2 = -1; /* get the max/min offsets in the delta time */ /*fixme: the stem height is not calculated yet*/ for (u = s; u; u = u->ts_next) { if (u->type == BAR) break; if (u->sflags & S_NEW_SY) { if (u != s) break; sy = sy->next; for (staff = nst; staff <= sy->nstaff; staff++) { stb[staff].nvoice = -1; for (i = 4; --i >= 0; ) { stb[staff].st[i].voice = -1; stb[staff].st[i].ymx = 0; stb[staff].st[i].ymn = 24; } } nst = sy->nstaff; } if (u->type != NOTEREST || (u->flags & ABC_F_INVIS)) continue; staff = u->staff; #if 1 /*fixme:test*/ if (staff > nst) { bug("set_stem_dir(): bad staff number\n", 1); } #endif voice = u->voice; if (vtb[voice].st1 < 0) { vtb[voice].st1 = staff; } else if (vtb[voice].st1 != staff) { if (staff > vtb[voice].st1) { if (staff > vtb[voice].st2) vtb[voice].st2 = staff; } else { if (vtb[voice].st1 > vtb[voice].st2) vtb[voice].st2 = vtb[voice].st1; vtb[voice].st1 = staff; } } rvoice = sy->voice[voice].range; for (i = stb[staff].nvoice; i >= 0; i--) { if (stb[staff].st[i].voice == rvoice) break; } if (i < 0) { if (++stb[staff].nvoice >= 4) bug("Too many voices per staff", 1); for (i = 0; i < stb[staff].nvoice; i++) { if (rvoice < stb[staff].st[i].voice) { memmove(&stb[staff].st[i + 1], &stb[staff].st[i], sizeof stb[staff].st[i] * (stb[staff].nvoice - i)); stb[staff].st[i].ymx = 0; stb[staff].st[i].ymn = 24; break; } } stb[staff].st[i].voice = rvoice; } if (u->abc_type != ABC_T_NOTE) continue; if (u->ymx > stb[staff].st[i].ymx) stb[staff].st[i].ymx = u->ymx; if (u->ymn < stb[staff].st[i].ymn) stb[staff].st[i].ymn = u->ymn; if (u->sflags & S_XSTEM) { if (u->ts_prev->staff != staff - 1 || u->ts_prev->abc_type != ABC_T_NOTE) { error(1, s, "Bad !xstem!"); u->sflags &= ~S_XSTEM; /*fixme:nflags KO*/ } else { u->ts_prev->multi = 1; u->multi = 1; u->flags |= ABC_F_STEMLESS; } } } for ( ; s != u; s = s->ts_next) { if (s->multi) continue; if (s->type != NOTEREST /* if not note nor rest */ && s->type != GRACE) continue; staff = s->staff; voice = s->voice; // if (!s->multi && vtb[voice].st2 >= 0) { if (vtb[voice].st2 >= 0) { if (staff == vtb[voice].st1) s->multi = -1; else if (staff == vtb[voice].st2) s->multi = 1; continue; } if (stb[staff].nvoice <= 0) { /* voice alone on the staff */ // if (s->multi) // continue; /*fixme:could be done in set_float()*/ if (s->sflags & S_FLOATING) { if (staff == voice_tb[voice].staff) s->multi = -1; else s->multi = 1; } continue; } rvoice = sy->voice[voice].range; for (i = stb[staff].nvoice; i >= 0; i--) { if (stb[staff].st[i].voice == rvoice) break; } if (i < 0) continue; /* voice ignored */ if (i == stb[staff].nvoice) { s->multi = -1; /* last voice */ } else { s->multi = 1; /* first voice(s) */ /* if 3 voices, and vertical space enough, * have stems down for the middle voice */ if (i != 0 && i + 1 == stb[staff].nvoice) { if (stb[staff].st[i].ymn - cfmt.stemheight > stb[staff].st[i + 1].ymx) s->multi = -1; /* special case for unison */ if (s->ts_prev && s->ts_prev->time == s->time && s->ts_prev->staff == s->staff && s->pits[s->nhd] == s->ts_prev->pits[0] && (s->sflags & (S_BEAM_ST | S_BEAM_END)) == (S_BEAM_ST | S_BEAM_END) && ((t = s->ts_next) == NULL || t->staff != s->staff || t->time != s->time)) s->multi = -1; } } } while (s && s->type == BAR) { if (s->sflags & S_NEW_SY) { sy = sy->next; nst = sy->nstaff; } s = s->ts_next; } } } /* -- adjust the offset of the rests when many voices -- */ /* this function is called only once per tune */ static void set_rest_offset(void) { struct SYSTEM *sy; struct SYMBOL *s, *s2; int nvoice, voice, end_time, not_alone, ymax, ymin, shift, dots; float dx; struct { struct SYMBOL *s; int staff; int end_time; } vtb[MAXVOICE], *v; memset(vtb, 0, sizeof vtb); sy = cursys; nvoice = 0; for (s = tsfirst; s; s = s->ts_next) { if (s->flags & ABC_F_INVIS) continue; if (s->sflags & S_NEW_SY) sy = sy->next; if (s->type != NOTEREST) continue; if (s->voice > nvoice) nvoice = s->voice; v = &vtb[s->voice]; v->s = s; v->staff = s->staff; v->end_time = s->time + s->dur; if (s->abc_type != ABC_T_REST) continue; /* check if clash with previous symbols */ ymin = -127; ymax = 127; not_alone = dots = 0; for (voice = 0, v = vtb; voice <= nvoice; voice++, v++) { s2 = v->s; if (!s2 || v->staff != s->staff || voice == s->voice) continue; if (v->end_time <= s->time) continue; not_alone++; if (sy->voice[voice].range < sy->voice[s->voice].range) { if (s2->time == s->time) { if (s2->ymn < ymax) { ymax = s2->ymn; if (s2->dots) dots = 1; } } else { if (s2->y < ymax) ymax = s2->y; } } else { if (s2->time == s->time) { if (s2->ymx > ymin) { ymin = s2->ymx; if (s2->dots) dots = 1; } } else { if (s2->y > ymin) ymin = s2->y; } } } /* check if clash with next symbols */ end_time = s->time + s->dur; for (s2 = s->ts_next; s2; s2 = s2->ts_next) { if (s2->time >= end_time) break; if (s2->staff != s->staff || s2->type != NOTEREST || (s2->flags & ABC_F_INVIS)) continue; not_alone++; if (sy->voice[s2->voice].range < sy->voice[s->voice].range) { if (s2->time == s->time) { if (s2->ymn < ymax) { ymax = s2->ymn; if (s2->dots) dots = 1; } } else { if (s2->y < ymax) ymax = s2->y; } } else { if (s2->time == s->time) { if (s2->ymx > ymin) { ymin = s2->ymx; if (s2->dots) dots = 1; } } else { if (s2->y > ymin) ymin = s2->y; } } } shift = ymax - s->ymx; if (shift < 0) { shift = (-shift + 5) / 6 * 6; if (s->ymn - shift >= ymin) { s->y -= shift; s->ymx -= shift; s->ymn -= shift; continue; } dx = dots ? 15 : 10; s->u.note.notes[0].shhd = dx; s->xmx = dx; continue; } shift = ymin - s->ymn; if (shift > 0) { shift = (shift + 5) / 6 * 6; if (s->ymx + shift <= ymax) { s->y += shift; s->ymx += shift; s->ymn += shift; continue; } dx = dots ? 15 : 10; s->u.note.notes[0].shhd = dx; s->xmx = dx; continue; } if (!not_alone) { s->y = 12; s->ymx = 24; s->ymn = 0; } } } /* -- create a starting symbol -- */ static struct SYMBOL *sym_new(int type, struct VOICE_S *p_voice, struct SYMBOL *last_s) /* same time */ { struct SYMBOL *s; s = (struct SYMBOL *) getarena(sizeof *s); memset(s, 0, sizeof *s); s->type = type; s->voice = p_voice - voice_tb; s->staff = p_voice->staff; s->time = last_s->time; s->next = p_voice->last_sym->next; if (s->next) s->next->prev = s; p_voice->last_sym->next = s; s->prev = p_voice->last_sym; p_voice->last_sym = s; s->ts_next = last_s; s->ts_prev = last_s->ts_prev; if (s->ts_prev) s->ts_prev->ts_next = s; if (!s->ts_prev || s->ts_prev->type != type) s->sflags |= S_SEQST; last_s->ts_prev = s; if (last_s->type == type && s->voice != last_s->voice) { last_s->sflags &= ~S_SEQST; last_s->shrink = 0; } s->fn = last_s->fn; s->linenum = last_s->linenum; s->colnum = last_s->colnum; return s; } /* -- init the symbols at start of a music line -- */ static void init_music_line(void) { struct VOICE_S *p_voice; struct SYMBOL *s, *last_s; int voice, staff; /* initialize the voices */ for (p_voice = first_voice; p_voice; p_voice = p_voice->next) { voice = p_voice - voice_tb; p_voice->last_sym = p_voice->sym; if (cursys->voice[voice].range < 0) continue; p_voice->second = cursys->voice[voice].second; /* move the voice to a non empty staff */ staff = cursys->voice[voice].staff; while (staff < nstaff && cursys->staff[staff].empty) staff++; p_voice->staff = staff; } /* add a clef at start of the main voices */ last_s = tsfirst; while (last_s && last_s->type == CLEF) { /* move the starting clefs */ voice = last_s->voice; p_voice = &voice_tb[voice]; if (cursys->voice[voice].range >= 0 && !cursys->voice[voice].second) { last_s->aux = 0; /* normal clef */ p_voice->last_sym = p_voice->sym = last_s; } last_s = last_s->ts_next; } for (p_voice = first_voice; p_voice; p_voice = p_voice->next) { if (p_voice->sym && p_voice->sym->type == CLEF) continue; voice = p_voice - voice_tb; if (cursys->voice[voice].range < 0 || cursys->voice[voice].second) continue; staff = cursys->voice[voice].staff; #if 0 if (last_s->voice == voice && last_s->type == CLEF) { last_s->aux = 0; /* normal clef */ #if 0 if (cursys->staff[staff].clef.invis) s->flags |= ABC_F_INVIS; #endif p_voice->last_sym = p_voice->sym = last_s; last_s = last_s->ts_next; continue; } #endif if (!staff_tb[staff].s_clef) continue; // no clef s = (struct SYMBOL *) getarena(sizeof *s); memset(s, 0, sizeof *s); memcpy(&s->u.clef, &staff_tb[staff].s_clef->u.clef, sizeof s->u.clef); s->type = CLEF; s->voice = voice; s->staff = staff; s->time = last_s ? last_s->time : 0; s->next = p_voice->sym; if (s->next) { s->next->prev = s; s->fn = s->next->fn; s->linenum = s->next->linenum; s->colnum = s->next->colnum; } p_voice->last_sym = p_voice->sym = s; s->ts_next = last_s; s->ts_prev = last_s ? last_s->ts_prev : NULL; if (!s->ts_prev) { tsfirst = s; s->sflags |= S_SEQST; } else { s->ts_prev->ts_next = s; } if (last_s) { last_s->ts_prev = s; if (last_s->type == CLEF) last_s->sflags &= ~S_SEQST; } // if (cursys->voice[voice].second) // s->sflags |= S_SECOND; if (staff_tb[staff].s_clef->u.clef.invis || cursys->staff[staff].empty) s->flags |= ABC_F_INVIS; // set_yval(s); } /* add keysig */ for (p_voice = first_voice; p_voice; p_voice = p_voice->next) { voice = p_voice - voice_tb; if (cursys->voice[voice].range < 0 || cursys->voice[voice].second || cursys->staff[cursys->voice[voice].staff].empty) continue; if (last_s && last_s->voice == voice && last_s->type == KEYSIG) { p_voice->last_sym = last_s; last_s->aux = last_s->u.key.sf; // no key cancel last_s = last_s->ts_next; continue; } if (p_voice->key.sf != 0 || p_voice->key.nacc != 0) { s = sym_new(KEYSIG, p_voice, last_s); memcpy(&s->u.key, &p_voice->key, sizeof s->u.key); if (s->u.key.instr == K_Hp) s->aux = 3; /* "A" -> "D" => G natural */ // set_yval(s); } } /* add time signature if needed */ if (insert_meter & 1) { for (p_voice = first_voice; p_voice; p_voice = p_voice->next) { voice = p_voice - voice_tb; if (cursys->voice[voice].range < 0 || cursys->voice[voice].second || cursys->staff[cursys->voice[voice].staff].empty || p_voice->meter.nmeter == 0) /* M:none */ continue; if (last_s && last_s->voice == voice && last_s->type == TIMESIG) { p_voice->last_sym = last_s; last_s = last_s->ts_next; continue; } s = sym_new(TIMESIG, p_voice, last_s); memcpy(&s->u.meter, &p_voice->meter, sizeof s->u.meter); // set_yval(s); } insert_meter &= ~1; // no meter any more } /* add bar if needed (for repeat bracket) */ for (p_voice = first_voice; p_voice; p_voice = p_voice->next) { int bar_start; // if bar already, keep it in sequence voice = p_voice - voice_tb; bar_start = p_voice->bar_start; p_voice->bar_start = 0; if (last_s && last_s->voice == voice && last_s->type == BAR) { p_voice->last_sym = last_s; last_s = last_s->ts_next; continue; } if (!bar_start) continue; if (cursys->voice[voice].range < 0 || cursys->voice[voice].second || cursys->staff[cursys->voice[voice].staff].empty) continue; s = sym_new(BAR, p_voice, last_s); s->u.bar.type = bar_start & 0x0fff; if (bar_start & 0x8000) s->flags |= ABC_F_INVIS; if (bar_start & 0x4000) s->sflags |= S_NOREPBRA; if (bar_start & 0x2000) s->flags |= ABC_F_RBSTART; if (bar_start & 0x1000) s->sflags |= S_RBSTART; s->text = p_voice->bar_text; s->gch = p_voice->bar_gch; if (p_voice->bar_repeat) s->u.bar.repeat_bar = p_voice->bar_repeat; p_voice->bar_repeat = 0; p_voice->bar_text = NULL; p_voice->bar_gch = NULL; } /* if initialization of a new music line, compute the spacing, * including the first (old) sequence */ set_pitch(last_s); s = last_s; if (s) { for ( ; s; s = s->ts_next) if (s->sflags & S_SEQST) break; if (s) for (s = s->ts_next; s; s = s->ts_next) if (s->sflags & S_SEQST) break; } set_allsymwidth(s); /* set the width of the added symbols */ } /* -- set a pitch in all symbols and the start/stop of the beams -- */ static void set_words(struct VOICE_S *p_voice) { int pitch, beam_start; struct SYMBOL *s, *s2, *lastnote; for (s = p_voice->sym; s; s = s->next) { if (s->abc_type == ABC_T_NOTE) { pitch = s->pits[0]; break; } } if (!s) pitch = 127; /* no note */ beam_start = 1; lastnote = NULL; for (s = p_voice->sym; s; s = s->next) { switch (s->type) { default: if (s->flags & ABC_F_SPACE) beam_start = 1; break; case MREST: beam_start = 1; break; case BAR: if (!(s->sflags & S_BEAM_ON)) beam_start = 1; /* change the last long note to the square note */ if (!s->next && s->prev && s->prev->abc_type == ABC_T_NOTE && s->prev->dur >= BREVE) s->prev->head = H_SQUARE; break; case NOTEREST: if (s->sflags & S_TREM2) break; if (s->flags & ABC_F_SPACE) beam_start = 1; if (beam_start || s->nflags - s->aux <= 0) { if (lastnote) { lastnote->sflags |= S_BEAM_END; lastnote = NULL; } if (s->nflags - s->aux <= 0) { s->sflags |= (S_BEAM_ST | S_BEAM_END); } else if (s->abc_type == ABC_T_NOTE) { s->sflags |= S_BEAM_ST; beam_start = 0; } } if (s->sflags & S_BEAM_END) beam_start = 1; if (s->abc_type == ABC_T_NOTE) lastnote = s; break; } if (s->abc_type == ABC_T_NOTE) { pitch = s->pits[0]; // if (s->prev // && s->prev->abc_type != ABC_T_NOTE) { // s->prev->pits[0] = // (s->prev->pits[0] + pitch) // / 2; for (s2 = s->prev; s2; s2 = s2->prev) { if (s2->abc_type != ABC_T_REST) break; s2->pits[0] = pitch; } } else { s->pits[0] = pitch; } } if (lastnote) lastnote->sflags |= S_BEAM_END; } /* -- set the end of the repeat sequences -- */ static void set_rb(struct VOICE_S *p_voice) { struct SYMBOL *s, *s2; int n; s = p_voice->sym; while (s) { if (s->type != BAR || !(s->sflags & S_RBSTART) || (s->sflags & S_NOREPBRA)) { s = s->next; continue; } n = 0; s2 = NULL; for (s = s->next; s; s = s->next) { if (s->type != BAR) continue; n++; if (s->sflags & S_RBSTOP) break; if (!s->next) { s->flags |= ABC_F_RBSTOP; s->sflags |= S_RBSTOP; break; } if (n == cfmt.rbmin) s2 = s; if (n == cfmt.rbmax) { if (s2) s = s2; s->sflags |= S_RBSTOP; break; } } } } /* -- initialize the generator -- */ /* this function is called only once per tune */ static void set_global(void) { struct SYSTEM *sy; struct SYMBOL *s; struct VOICE_S *p_voice; int staff; static const signed char delpit[4] = {0, -7, -14, 0}; /* get the max number of staves */ sy = cursys; staff = cursys->nstaff; while ((sy = sy->next) != NULL) { if (sy->nstaff > staff) staff = sy->nstaff; } nstaff = staff; /* adjust the pitches if old abc2ps behaviour of clef definition */ if (cfmt.abc2pscompat) { int i; for (p_voice = first_voice; p_voice; p_voice = p_voice->next) { int delta; struct SYMBOL *g; if (p_voice->octave != 0) continue; #if 0 /* (the clefs in the voice table are not yet initialized) */ // i = p_voice->staff; // i = cursys->staff[i].clef.type; i = cursys->voice[p_voice - voice_tb].clef.type; #else i = p_voice->s_clef->u.clef.type; #endif if (i == PERC) continue; delta = delpit[i]; for (s = p_voice->sym; s; s = s->next) { switch (s->type) { case CLEF: i = s->u.clef.type; if (!s->u.clef.check_pitch) i = 0; delta = delpit[i]; break; case NOTEREST: if (delta == 0) break; if (s->abc_type == ABC_T_REST) break; for (i = s->nhd; i >= 0; i--) s->pits[i] += delta; break; case GRACE: if (delta == 0) break; for (g = s->extra; g; g = g->next) { if (g->type != NOTEREST) continue; for (i = g->nhd; i >= 0; i--) g->pits[i] += delta; } break; } } } } /* set the pitches, the words (beams) and the repeat brackets */ for (p_voice = first_voice; p_voice; p_voice = p_voice->next) { set_words(p_voice); // if (!p_voice->second && !p_voice->norepbra) set_rb(p_voice); } /* set the staff of the floating voices */ set_float(); // set the clefs and adjust the pitches of all symbols set_clefs(); set_pitch(NULL); } /* -- return the left indentation of the staves -- */ static float set_indent(void) { int staff, voice; float w, maxw; struct VOICE_S *p_voice; char *p, *q; maxw = 0; for (p_voice = first_voice; p_voice; p_voice = p_voice->next) { voice = p_voice - voice_tb; if (cursys->voice[voice].range < 0) continue; staff = cursys->voice[voice].staff; if (cursys->staff[staff].empty) continue; if ((p = p_voice->new_name ? p_voice->nm : p_voice->snm) == NULL) continue; str_font(VOICEFONT); for (;;) { if ((q = strstr(p, "\\n")) != NULL) *q = '\0'; w = tex_str(p); if (w > maxw) maxw = w; if (!q) break; *q = '\\'; p = q + 2; } } if (maxw != 0) { w = 0; // for (staff = 0; staff <= nstaff; staff++) { for (staff = 0; staff <= cursys->nstaff; staff++) { if (cursys->staff[staff].flags & (OPEN_BRACE2 | OPEN_BRACKET2)) { w = 20; break; } if ((cursys->staff[staff].flags & (OPEN_BRACE | OPEN_BRACKET)) && w == 0) w = 10; } maxw += 4 * cwid(' ') * cfmt.font_tb[VOICEFONT].swfac + w; } if (insert_meter & 2) /* if indent */ maxw += cfmt.indent; return maxw; } /* -- decide on beams and on stem directions -- */ /* this routine is called only once per tune */ static void set_beams(struct SYMBOL *sym) { struct SYSTEM *sy; struct SYMBOL *s, *t, *g, *s_opp; int n, m, beam, laststem, mid_p; beam = 0; laststem = -1; s_opp = NULL; sy = cursys; for (s = sym; s; s = s->next) { if (s->abc_type != ABC_T_NOTE) { switch (s->type) { default: continue; case STAVES: sy = sy->next; continue; case GRACE: break; } g = s->extra; while (g->abc_type != ABC_T_NOTE) g = g->next; if (g->stem == 2) { /* opposite gstem direction */ s_opp = s; continue; } if (s->stem == 0 && (s->stem = s->multi) == 0) s->stem = 1; for (; g; g = g->next) { g->stem = s->stem; g->multi = s->multi; } continue; } mid_p = s->mid / 3 + 18; if (s->stem == 0 /* if not explicitly set */ && (s->stem = s->multi) == 0) { /* and alone on the staff */ /* notes in a beam have the same stem direction */ if (beam) { s->stem = laststem; } else if ((s->sflags & (S_BEAM_ST | S_BEAM_END)) == S_BEAM_ST) { /* start of beam */ int pu = s->pits[s->nhd], pd = s->pits[0]; beam = 1; for (t = s->next; t; t = t->next) { if (t->abc_type != ABC_T_NOTE) continue; if (t->stem || t->multi) { s->stem = t->multi ? t->multi : t->stem; break; } if (t->pits[t->nhd] > pu) pu = t->pits[t->nhd]; if (t->pits[0] < pd) pd = t->pits[0]; if (t->sflags & S_BEAM_END) break; } if (t->sflags & S_BEAM_END) { mid_p *= 2; if (pu + pd < mid_p) { s->stem = 1; } else if (pu + pd > mid_p) { s->stem = -1; } else { if (cfmt.bstemdown) s->stem = -1; } } if (!s->stem) s->stem = laststem; } else { // no beam n = s->pits[s->nhd] + s->pits[0]; if (n == mid_p * 2) { n = 0; for (m = 0; m <= s->nhd; m++) n += s->pits[m]; mid_p *= s->nhd + 1; } else { mid_p *= 2; } if (n < mid_p) s->stem = 1; else if (n > mid_p) s->stem = -1; else if (cfmt.bstemdown) s->stem = -1; else s->stem = laststem; } } else { /* stem set by set_stem_dir */ if ((s->sflags & (S_BEAM_ST | S_BEAM_END)) == S_BEAM_ST) /* start of beam */ beam = 1; } if (s->sflags & S_BEAM_END) beam = 0; laststem = s->stem; if (s_opp) { /* opposite gstem direction */ for (g = s_opp->extra; g; g = g->next) g->stem = -laststem; s_opp->stem = -laststem; s_opp = NULL; } } } /* handle unison in voice overlap */ static int same_head(struct SYMBOL *s1, struct SYMBOL *s2) { int i1, i2, l1, l2, i11, i12, i21, i22; float sh1, sh2; if ((s1->sflags & (S_SHIFTUNISON_1 | S_SHIFTUNISON_2)) == (S_SHIFTUNISON_1 | S_SHIFTUNISON_2)) return 0; if ((l1 = s1->dur) >= SEMIBREVE) return 0; if ((l2 = s2->dur) >= SEMIBREVE) return 0; if (s1->flags & s2->flags & ABC_F_STEMLESS) return 0; if (s1->dots != s2->dots) { // if ((s1->sflags & (S_SHIFTUNISON_1 | S_SHIFTUNISON_2)) if ((s1->sflags & S_SHIFTUNISON_1) || s1->dots * s2->dots != 0) return 0; } if (s1->stem * s2->stem > 0) return 0; /* check if a common unison */ i1 = i2 = 0; if (s1->pits[0] > s2->pits[0]) { if (s1->stem < 0) return 0; while (s2->pits[i2] != s1->pits[0]) { if (++i2 > s2->nhd) return 0; } } else if (s1->pits[0] < s2->pits[0]) { if (s2->stem < 0) return 0; while (s2->pits[0] != s1->pits[i1]) { if (++i1 > s1->nhd) return 0; } } if (s2->u.note.notes[i2].acc != s1->u.note.notes[i1].acc) return 0; i11 = i1; i21 = i2; sh1 = s1->u.note.notes[i1].shhd; sh2 = s2->u.note.notes[i2].shhd; do { i1++; i2++; if (i1 > s1->nhd) { // if (s1->pits[0] < s2->pits[0]) // return 0; break; } if (i2 > s2->nhd) { // if (s1->pits[0] > s2->pits[0]) // return 0; break; } if (s2->u.note.notes[i2].acc != s1->u.note.notes[i1].acc) return 0; if (sh1 < s1->u.note.notes[i1].shhd) sh1 = s1->u.note.notes[i1].shhd; if (sh2 < s2->u.note.notes[i2].shhd) sh2 = s2->u.note.notes[i2].shhd; } while (s2->pits[i2] == s1->pits[i1]); if (i1 <= s1->nhd) { if (i2 <= s2->nhd) return 0; if (s2->stem > 0) return 0; } else if (i2 <= s2->nhd) { if (s1->stem > 0) return 0; } i12 = i1; i22 = i2; if (l1 == l2) goto same_head; if (l1 < l2) { l1 = l2; l2 = s1->dur; } if (l1 < MINIM) { if (s2->dots > 0) goto head_2; if (s1->dots > 0) goto head_1; goto same_head; } if (l2 < CROTCHET) { /* (l1 >= MINIM) */ // if ((s1->sflags & S_SHIFTUNISON_2) // || s1->dots != s2->dots) if (s1->sflags & S_SHIFTUNISON_2) return 0; if (s2->dur >= MINIM) goto head_2; goto head_1; } return 0; same_head: if (voice_tb[s1->voice].scale < voice_tb[s2->voice].scale) goto head_2; head_1: // s2->nohdi1 = i21; /* keep heads of 1st voice */ // s2->nohdi2 = i22; for (i2 = i21; i2 < i22; i2++) { s2->u.note.notes[i2].invisible = 1; s2->u.note.notes[i2].acc = 0; } for (i2 = 0; i2 <= s2->nhd; i2++) s2->u.note.notes[i2].shhd += sh1; return 1; head_2: // s1->nohdi1 = i11; /* keep heads of 2nd voice */ // s1->nohdi2 = i12; for (i1 = i11; i1 < i12; i1++) { s1->u.note.notes[i1].invisible = 1; s1->u.note.notes[i1].acc = 0; } for (i1 = 0; i1 <= s1->nhd; i1++) s1->u.note.notes[i1].shhd += sh2; return 1; } /* width of notes for voice overlap - index = head */ static float w_note[] = { 3.5, 3.7, 5, 7 }; /* handle unison with different accidentals */ static void unison_acc(struct SYMBOL *s1, struct SYMBOL *s2, int i1, int i2) { int m; float d; if (s2->u.note.notes[i2].acc == 0) { d = w_note[s2->head] * 2 + s2->xmx + s1->u.note.notes[i1].shac + 2; if (s1->u.note.notes[i1].acc & 0xf8) d += 2; if (s2->dots) d += 6; for (m = 0; m <= s1->nhd; m++) { s1->u.note.notes[m].shhd += d; s1->u.note.notes[m].shac -= d; } s1->xmx += d; } else { d = w_note[s1->head] * 2 + s1->xmx + s2->u.note.notes[i2].shac + 2; if (s2->u.note.notes[i2].acc & 0xf8) d += 2; if (s1->dots) d += 6; for (m = 0; m <= s2->nhd; m++) { s2->u.note.notes[m].shhd += d; s2->u.note.notes[m].shac -= d; } s2->xmx += d; } } #define MAXPIT (48 * 2) /* set the left space of a note/chord */ static void set_left(struct SYMBOL *s, float *left) { int m, i, j; float w_base, w, shift; for (i = 0; i < MAXPIT; i++) left[i] = -100; /* stem */ w = w_base = w_note[s->head]; if (s->nflags > -2) { if (s->stem > 0) { w = -w; i = s->pits[0] * 2; j = ((int) ((s->ymx - 2) / 3) + 18) * 2; } else { i = ((int) ((s->ymn + 2) / 3) + 18) * 2; j = s->pits[s->nhd] * 2; } if (i < 0) i = 0; for (; i < MAXPIT && i <= j; i++) left[i] = w; } /* notes */ if (s->stem > 0) shift = s->u.note.notes[0].shhd; /* previous shift */ else shift = s->u.note.notes[s->nhd].shhd; for (m = 0; m <= s->nhd; m++) { w = -s->u.note.notes[m].shhd + w_base + shift; i = s->pits[m] * 2; if (i < 0) i = 0; else if (i >= MAXPIT - 1) i = MAXPIT - 2; if (w > left[i]) left[i] = w; if (s->head != H_SQUARE) w -= 1; if (w > left[i - 1]) left[i - 1] = w; if (w > left[i + 1]) left[i + 1] = w; } } /* set the right space of a note/chord */ static void set_right(struct SYMBOL *s, float *right) { int m, i, j, k, flags; float w_base, w, shift; for (i = 0; i < MAXPIT; i++) right[i] = -100; /* stem and flags */ flags = s->nflags > 0 && (s->sflags & (S_BEAM_ST | S_BEAM_END)) == (S_BEAM_ST | S_BEAM_END); w = w_base = w_note[s->head]; if (s->nflags > -2) { if (s->stem < 0) { w = -w; i = ((int) ((s->ymn + 2) / 3) + 18) * 2; j = s->pits[s->nhd] * 2; k = i + 4; } else { i = s->pits[0] * 2; j = ((int) ((s->ymx - 2) / 3) + 18) * 2; k = i; // (have gcc happy) } if (i < 0) i = 0; for ( ; i < MAXPIT && i < j; i++) right[i] = w; } if (flags) { if (s->stem > 0) { if (s->xmx == 0) i = s->pits[s->nhd] * 2; else i = s->pits[0] * 2; i += 4; if (i < 0) i = 0; for (; i < MAXPIT && i <= j - 4; i++) right[i] = 11; } else { i = k; if (i < 0) i = 0; for (; i < MAXPIT && i <= s->pits[0] * 2 - 4; i++) right[i] = 3.5; } } /* notes */ if (s->stem > 0) shift = s->u.note.notes[0].shhd; /* previous shift */ else shift = s->u.note.notes[s->nhd].shhd; for (m = 0; m <= s->nhd; m++) { w = s->u.note.notes[m].shhd + w_base - shift; i = s->pits[m] * 2; if (i < 0) i = 0; else if (i >= MAXPIT - 1) i = MAXPIT - 2; if (w > right[i]) right[i] = w; if (s->head != H_SQUARE) w -= 1; if (w > right[i - 1]) right[i - 1] = w; if (w > right[i + 1]) right[i + 1] = w; } } /* -- shift the notes horizontally when voices overlap -- */ /* this routine is called only once per tune */ static void set_overlap(void) { struct SYMBOL *s, *s1, *s2, *s3; int i, i1, i2, m, sd, t, dp; float d, d2, dr, dr2, dx; float left1[MAXPIT], right1[MAXPIT], left2[MAXPIT], right2[MAXPIT]; float right3[MAXPIT], *pl, *pr; for (s = tsfirst; s; s = s->ts_next) { if (s->abc_type != ABC_T_NOTE || (s->flags & ABC_F_INVIS)) continue; /* treat the stem on two staves with different directions */ if ((s->sflags & S_XSTEM) && s->ts_prev->stem < 0) { s2 = s->ts_prev; for (m = 0; m <= s2->nhd; m++) { s2->u.note.notes[m].shhd += STEM_XOFF * 2; s2->u.note.notes[m].shac -= STEM_XOFF * 2; } s2->xmx += STEM_XOFF * 2; } /* search the next note at the same time on the same staff */ s2 = s; for (;;) { s2 = s2->ts_next; if (!s2) break; if (s2->time != s->time) { s2 = NULL; break; } if (s2->abc_type == ABC_T_NOTE && !(s2->flags & ABC_F_INVIS) && s2->staff == s->staff) break; } if (!s2) continue; s1 = s; /* set the dot vertical offset */ if (cursys->voice[s1->voice].range < cursys->voice[s2->voice].range) s2->doty = -3; else s1->doty = -3; /* no shift if no overlap */ if (s1->ymn > s2->ymx || s1->ymx < s2->ymn) continue; if (same_head(s1, s2)) continue; /* compute the minimum space for 's1 s2' and 's2 s1' */ set_right(s1, right1); set_left(s2, left2); s3 = s1->ts_prev; if (s3 && s3->time == s1->time && s3->staff == s1->staff && s3->abc_type == ABC_T_NOTE && !(s3->flags & ABC_F_INVIS)) { set_right(s3, right3); for (i = 0; i < MAXPIT; i++) { if (right3[i] > right1[i]) right1[i] = right3[i]; } } else { s3 = NULL; } d = -100; for (i = 0; i < MAXPIT; i++) { if (left2[i] + right1[i] > d) d = left2[i] + right1[i]; } if (d < -3) { // no clash if no dots clash if (!s1->dots || !s2->dots || s2->doty >= 0 || s1->stem > 0 || s2->stem < 0 || s1->pits[s1->nhd] + 2 != s2->pits[0] || (s2->pits[0] & 1)) continue; } set_right(s2, right2); set_left(s1, left1); if (s3) { set_left(s3, right3); for (i = 0; i < MAXPIT; i++) { if (right3[i] > left1[i]) left1[i] = right3[i]; } } d2 = dr = dr2 = -100; for (i = 0; i < MAXPIT; i++) { if (left1[i] + right2[i] > d2) d2 = left1[i] + right2[i]; if (right1[i] > dr) dr = right1[i]; if (right2[i] > dr2) dr2 = right2[i]; } /* check for unison with different accidentals * and clash of dots */ t = 0; i1 = s1->nhd; i2 = s2->nhd; for (;;) { dp = s1->pits[i1] - s2->pits[i2]; switch (dp) { case 0: if (s1->u.note.notes[i1].acc != s2->u.note.notes[i2].acc) { t = -1; break; } if (s2->u.note.notes[i2].acc) s2->u.note.notes[i2].acc = 0; if (s1->dots && s2->dots && (s1->pits[i1] & 1)) t = 1; break; case -1: // if (s1->dots && s2->dots) // t = 1; if (s1->dots && s2->dots) { if (s1->pits[i1] & 1) { s1->doty = 0; s2->doty = 0; } else { s1->doty = -3; s2->doty = -3; } } break; case -2: if (s1->dots && s2->dots && !(s1->pits[i1] & 1)) { // t = 1; s1->doty = 0; s2->doty = 0; break; } break; } if (t < 0) break; if (dp >= 0) { if (--i1 < 0) break; } if (dp <= 0) { if (--i2 < 0) break; } } if (t < 0) { /* unison and different accidentals */ unison_acc(s1, s2, i1, i2); continue; } sd = 0; pl = left2; pr = right2; if (s1->dots) { if (s2->dots) { if (!t) /* if no dot clash */ sd = 1; /* align the dots */ } } else if (s2->dots) { if (d2 + dr < d + dr2) sd = 1; /* align the dots */ } if (!s3 && d2 + dr < d + dr2) { s1 = s2; /* invert the voices */ s2 = s; d = d2; pl = left1; pr = right1; dr2 = dr; } d += 3; if (d < 0) d = 0; // (not return!) /* handle the previous shift */ m = s1->stem >= 0 ? 0 : s1->nhd; d += s1->u.note.notes[m].shhd; m = s2->stem >= 0 ? 0 : s2->nhd; d -= s2->u.note.notes[m].shhd; /* * room for the dots * - if the dots of v1 don't shift, adjust the shift of v2 * - otherwise, align the dots and shift them if clash */ if (s1->dots) { dx = 7.7 + s1->xmx + // x 1st dot 3.5 * s1->dots - 3.5 + // x last dot 3; // some space if (!sd) { d2 = -100; for (i1 = 0; i1 <= s1->nhd; i1++) { i = s1->pits[i1]; if (!(i & 1)) { if (s1->doty >= 0) i++; else i--; } i *= 2; if (i < 1) i = 1; else if (i >= MAXPIT - 1) i = MAXPIT - 2; if (pl[i] > d2) d2 = pl[i]; if (pl[i - 1] + 1 > d2) d2 = pl[i - 1] + 1; if (pl[i + 1] + 1 > d2) d2 = pl[i + 1] + 1; } if (dx + d2 + 2 > d) d = dx + d2 + 2; } else { if (dx < d + dr2 + s2->xmx) { d2 = 0; for (i1 = 0; i1 <= s1->nhd; i1++) { i = s1->pits[i1]; if (!(i & 1)) { if (s1->doty >= 0) i++; else i--; } i *= 2; if (i < 1) i = 1; else if (i >= MAXPIT - 1) i = MAXPIT - 2; if (pr[i] > d2) d2 = pr[i]; if (pr[i - 1] + 1> d2) d2 = pr[i - 1] = 1; if (pr[i + 1] + 1 > d2) d2 = pr[i + 1] + 1; } if (d2 > 4.5 && 7.7 + s1->xmx + 2 < d + d2 + s2->xmx) s2->xmx = d2 + 3 - 7.7; } } } for (m = s2->nhd; m >= 0; m--) { s2->u.note.notes[m].shhd += d; // if (s2->u.note.accs[m] != 0 // && s2->pits[m] < s1->pits[0] - 4) // s2->shac[m] -= d; } s2->xmx += d; if (sd) s1->xmx = s2->xmx; // align the dots } } /* -- set the stem lengths -- */ /* this routine is called only once per tune */ static void set_stems(void) { struct SYSTEM *sy; struct SYMBOL *s, *s2, *g; float slen, scale; int ymn, ymx, nflags, mid; sy = cursys; for (s = tsfirst; s; s = s->ts_next) { if (s->abc_type != ABC_T_NOTE) { int ymin, ymax; switch (s->type) { default: continue; case STAVES: sy = sy->next; continue; case GRACE: break; } ymin = ymax = s->mid; for (g = s->extra; g; g = g->next) { if (g->type != NOTEREST) continue; slen = GSTEM; if (g->nflags > 1) slen += 1.2 * (g->nflags - 1); ymn = 3 * (g->pits[0] - 18); ymx = 3 * (g->pits[g->nhd] - 18); if (s->stem >= 0) { g->y = ymn; g->ys = ymx + slen; ymx = (int) (g->ys + 0.5); } else { g->y = ymx; g->ys = ymn - slen; ymn = (int) (g->ys - 0.5); } ymx += 2; ymn -= 2; if (ymn < ymin) ymin = ymn; else if (ymx > ymax) ymax = ymx; g->ymx = ymx; g->ymn = ymn; } s->ymx = ymax; s->ymn = ymin; continue; } /* shift notes in chords (need stem direction to do this) */ set_head_shift(s); /* if start or end of beam, adjust the number of flags * with the other end */ nflags = s->nflags; if ((s->sflags & (S_BEAM_ST | S_BEAM_END)) == S_BEAM_ST) { if (s->sflags & S_FEATHERED_BEAM) nflags = ++s->nflags; for (s2 = s->next; /*s2*/; s2 = s2->next) { if (s2->abc_type == ABC_T_NOTE) { if (s->sflags & S_FEATHERED_BEAM) s2->nflags++; if (s2->sflags & S_BEAM_END) break; } } /* if (s2) */ if (s2->nflags > nflags) nflags = s2->nflags; } else if ((s->sflags & (S_BEAM_ST | S_BEAM_END)) == S_BEAM_END) { for (s2 = s->prev; /*s2*/; s2 = s2->prev) { if (s2->sflags & S_BEAM_ST) break; } /* if (s2) */ if (s2->nflags > nflags) nflags = s2->nflags; } /* set height of stem end */ mid = s->mid; slen = cfmt.stemheight; switch (nflags) { case 2: slen += 2; break; case 3: slen += 5; break; case 4: slen += 10; break; case 5: slen += 16; break; } if ((scale = voice_tb[s->voice].scale) != 1) slen *= (scale + 1) * 0.5; ymn = 3 * (s->pits[0] - 18); if (s->nhd > 0) { slen -= 2; ymx = 3 * (s->pits[s->nhd] - 18); } else { ymx = ymn; } if (s->aux != 0) slen += 2 * s->aux; /* tremolo */ if (s->flags & ABC_F_STEMLESS) { if (s->stem >= 0) { s->y = ymn; s->ys = ymx; } else { s->ys = ymn; s->y = ymx; } if (nflags == -4) /* if longa */ ymn -= 6; s->ymx = ymx + 4; s->ymn = ymn - 4; } else if (s->stem >= 0) { if (nflags >= 2) slen -= 1; if (s->pits[s->nhd] > 26 && (nflags <= 0 || (s->sflags & (S_BEAM_ST | S_BEAM_END)) != (S_BEAM_ST | S_BEAM_END))) { slen -= 2; if (s->pits[s->nhd] > 28) slen -= 2; } s->y = ymn; if (s->u.note.notes[0].ti1 != 0) /*fixme * || s->u.note.ti2[0] != 0) */ ymn -= 3; s->ymn = ymn - 4; s->ys = ymx + slen; if (s->ys < mid) s->ys = mid; s->ymx = (int) (s->ys + 2.5); } else { /* stem down */ if (s->pits[0] < 18 && (nflags <= 0 || (s->sflags & (S_BEAM_ST | S_BEAM_END)) != (S_BEAM_ST | S_BEAM_END))) { slen -= 2; if (s->pits[0] < 16) slen -= 2; } s->ys = ymn - slen; if (s->ys > mid) s->ys = mid; s->ymn = (int) (s->ys - 2.5); s->y = ymx; /*fixme:the tie may be lower*/ if (s->u.note.notes[s->nhd].ti1 != 0) ymx += 3; s->ymx = ymx + 4; } } } /* -- split up unsuitable bars at end of staff -- */ static void check_bar(struct SYMBOL *s) { struct VOICE_S *p_voice; int bar_type, i; p_voice = &voice_tb[s->voice]; /* search the last bar */ while (s->type == CLEF || s->type == KEYSIG || s->type == TIMESIG) { if (s->type == TIMESIG && s->time > p_voice->sym->time) /* if not empty voice */ insert_meter |= 1; /* meter in the next line */ if ((s = s->prev) == NULL) return; } if (s->type != BAR) return; if (s->u.bar.repeat_bar) { p_voice->bar_start = B_OBRA; p_voice->bar_text = s->text; p_voice->bar_gch = s->gch; p_voice->bar_repeat = 1; s->text = NULL; s->gch = NULL; s->u.bar.repeat_bar = 0; if (s->flags & ABC_F_INVIS) p_voice->bar_start |= 0x8000; if (s->sflags & S_NOREPBRA) p_voice->bar_start |= 0x4000; if (s->flags & ABC_F_RBSTART) p_voice->bar_start |= 0x2000; if (s->sflags & S_RBSTART) p_voice->bar_start |= 0x1000; } bar_type = s->u.bar.type; if (bar_type == B_COL) /* ':' */ return; if ((bar_type & 0x0f) != B_COL) /* if not left repeat bar */ return; if (!(s->sflags & S_RRBAR)) { /* 'xx:' (not ':xx:') */ if (bar_type == ((B_SINGLE << 8) | B_LREP)) { p_voice->bar_start = B_LREP; s->u.bar.type = B_DOUBLE; return; } p_voice->bar_start = bar_type & 0x0fff; if (s->flags & ABC_F_INVIS) p_voice->bar_start |= 0x8000; if (s->sflags & S_NOREPBRA) p_voice->bar_start |= 0x4000; if (s->prev && s->prev->type == BAR) unlksym(s); else s->u.bar.type = B_BAR; return; } if (bar_type == B_DREP) { /* '::' */ s->u.bar.type = B_RREP; p_voice->bar_start = B_LREP; if (s->flags & ABC_F_INVIS) p_voice->bar_start |= 0x8000; if (s->sflags & S_NOREPBRA) p_voice->bar_start |= 0x4000; if (s->flags & ABC_F_RBSTART) p_voice->bar_start |= 0x2000; if (s->sflags & S_RBSTART) p_voice->bar_start |= 0x1000; return; } for (i = 0; bar_type != 0; i++) bar_type >>= 4; bar_type = s->u.bar.type; s->u.bar.type = bar_type >> ((i / 2) * 4); i = ((i + 1) / 2 * 4); bar_type &= 0x0fff; p_voice->bar_start = bar_type & ((1 << i) - 1); if (s->flags & ABC_F_INVIS) p_voice->bar_start |= 0x8000; if (s->sflags & S_NOREPBRA) p_voice->bar_start |= 0x4000; if (s->flags & ABC_F_RBSTART) p_voice->bar_start |= 0x2000; if (s->sflags & S_RBSTART) p_voice->bar_start |= 0x1000; } /* -- move the symbols of an empty staff to the next one -- */ static void sym_staff_move(int staff) // struct SYMBOL *s, // struct SYSTEM *sy) { struct SYMBOL *s; // for (;;) { for (s = tsfirst; s; s = s->ts_next) { if (s->sflags & S_NL) break; if (s->staff == staff && s->type != CLEF) { s->staff++; s->flags |= ABC_F_INVIS; } // s = s->ts_next; // if (s == tsnext || s->sflags & S_NEW_SY) // break; } } /* -- adjust the empty flag of a brace system -- */ static void set_brace(struct SYSTEM *sy, char *empty, char *empty_gl) { int staff, i, empty_fl; /* if a system brace has empty and non empty staves, keep all staves */ for (staff = 0; staff <= nstaff; staff++) { if (!(sy->staff[staff].flags & (OPEN_BRACE | OPEN_BRACE2))) continue; empty_fl = 0; i = staff; while (staff <= nstaff) { empty_fl |= empty[staff] ? 1 : 2; if (cursys->staff[staff].flags & (CLOSE_BRACE | CLOSE_BRACE2)) break; staff++; } if (empty_fl == 3) { /* if empty and not empty staves */ while (i <= staff) { empty[i] = 0; empty_gl[i++] = 0; } } } } /* -- define the start and end of a piece of tune -- */ /* tsnext becomes the beginning of the next line */ static void set_piece(void) { struct SYSTEM *sy; struct SYMBOL *s; struct VOICE_S *p_voice; struct STAFF_S *p_staff; int staff; char empty[MAXSTAFF], empty_gl[MAXSTAFF]; /* reset the staves */ sy = cursys; for (staff = 0; staff <= nstaff; staff++) { p_staff = &staff_tb[staff]; p_staff->y = 0; /* staff system not computed */ p_staff->stafflines = sy->staff[staff].stafflines; p_staff->staffscale = sy->staff[staff].staffscale; } /* search the next end of line, * set the repeat measures, (remove some dble bars?) * and flag the empty staves */ memset(empty, 1, sizeof empty); memset(empty_gl, 1, sizeof empty_gl); for (s = tsfirst; s; s = s->ts_next) { if (s->sflags & S_NL) break; if (s->sflags & S_NEW_SY) { set_brace(sy, empty, empty_gl); for (staff = 0; staff <= nstaff; staff++) { sy->staff[staff].empty = empty[staff]; empty[staff] = 1; } sy = sy->next; for (staff = 0; staff <= sy->nstaff; staff++) { p_staff = &staff_tb[staff]; p_staff->stafflines = sy->staff[staff].stafflines; if (!p_staff->stafflines) p_staff->stafflines = "|||||"; p_staff->staffscale = sy->staff[staff].staffscale; if (p_staff->staffscale == 0) p_staff->staffscale = 1; } } if (!empty[s->staff]) continue; switch (s->type) { case GRACE: empty_gl[s->staff] = empty[s->staff] = 0; break; case NOTEREST: case SPACE: case MREST: if (cfmt.staffnonote > 1) { empty_gl[s->staff] = empty[s->staff] = 0; } else if (!(s->flags & ABC_F_INVIS)) { if (s->abc_type == ABC_T_NOTE || cfmt.staffnonote != 0) empty_gl[s->staff] = empty[s->staff] = 0; } break; } } tsnext = s; /* set the last empty staves */ set_brace(sy, empty, empty_gl); for (staff = 0; staff <= nstaff; staff++) sy->staff[staff].empty = empty[staff]; /* define the offsets of the measure bars */ for (staff = 0; staff <= nstaff; staff++) { int i, l; char *stafflines; if (empty_gl[staff]) continue; p_staff = &staff_tb[staff]; stafflines = p_staff->stafflines; l = strlen(stafflines); p_staff->topbar = 6 * (l - 1); for (i = 0; i < l - 1; i++) if (stafflines[i] != '.') break; p_staff->botbar = i * 6; if (i >= l - 2) { // 0, 1 or 2 lines p_staff->botbar -= 6; p_staff->topbar += 6; } } /* move the symbols of the empty staves to the next staff */ // sy = cursys; for (staff = 0; staff < nstaff; staff++) { #if 1 if (empty_gl[staff]) sym_staff_move(staff); #else if (sy->staff[staff].empty) sym_staff_move(staff, tsfirst, sy); } if (sy->next) { for (s = tsfirst; s; s = s->ts_next) { if (s->sflags & S_NL) break; if (s->sflags & S_NEW_SY) { sy = sy->next; for (staff = 0; staff < nstaff; staff++) { if (sy->staff[staff].empty) sym_staff_move(staff, s, sy); } if (!sy->next) break; } } #endif } /* initialize the music line */ init_music_line(); /* if last music line, nothing more to do */ if (!tsnext) return; s = tsnext; s->sflags &= ~S_NL; s = s->ts_prev; s->ts_next = NULL; /* set the end of the voices */ for (p_voice = first_voice; p_voice; p_voice = p_voice->next) { int voice; voice = p_voice - voice_tb; for (s = tsnext->ts_prev; s; s = s->ts_prev) { if (s->voice == voice) { s->next = NULL; check_bar(s); break; } } if (!s) p_voice->sym = NULL; } } /* -- position the symbols along the staff -- */ static void set_sym_glue(float width) { struct SYMBOL *s; float beta0, alfa, beta; int some_grace; float xmin, x, xmax, spafac; /* calculate the whole space of the symbols */ some_grace = 0; xmin = x = xmax = 0; s = tsfirst; for (;;) { if (s->type == GRACE) some_grace = 1; if (s->sflags & S_SEQST) { float space; xmin += s->shrink; if ((space = s->space) < s->shrink) space = s->shrink; x += space; if (cfmt.stretchstaff) space *= 1.8; xmax += space; } if (!s->ts_next) break; s = s->ts_next; } /* set max shrink and stretch */ if (!cfmt.continueall) beta0 = BETA_X; else beta0 = BETA_C; /* memorize the glue for the last music line */ if (tsnext) { if (x - width >= 0) { beta_last = 0; } else { beta_last = (width - x) / (xmax - x); /* stretch */ if (beta_last > beta0) { if (cfmt.stretchstaff) { if (!cfmt.continueall && cfmt.linewarn) { error(0, s, "Line underfull (%.0fpt of %.0fpt)", beta0 * xmax + (1 - beta0) * x, width); } } else { width = x; beta_last = 0; } } } } else { /* if last music line */ if (x < width) { beta = (width - x) / (xmax - x); /* stretch */ if (beta >= beta_last) { beta = beta_last * xmax + (1 - beta_last) * x; /* shrink underfull last line same as previous */ if (beta < width * (1. - cfmt.stretchlast)) width = beta; } } } spafac = width / x; /* space expansion factor */ /* define the x offsets of all starting symbols */ x = xmax = 0; s = tsfirst; for (;;) { if (s->sflags & S_SEQST) { float new_space; new_space = s->shrink; if (s->space != 0) { if (new_space < s->space * spafac) new_space = s->space * spafac; xmax += s->space * spafac * 1.8; } x += new_space; xmax += new_space; s->x = x; s->xmax = xmax; } if (!s->ts_next) break; s = s->ts_next; } /* if the last symbol is not a bar, add some extra space */ switch (s->type) { case BAR: case FMTCHG: break; case CUSTOS: x += s->wr; xmin += s->wr; xmax += s->wr; break; default: { float min; min = s->wr; while (!(s->sflags & S_SEQST)) { s = s->ts_prev; if (s->wr > min) min = s->wr; } xmin += min + 3; if (tsnext && tsnext->space * 0.8 > s->wr + 4) { x += tsnext->space * 0.8 * spafac; xmax += tsnext->space * 0.8 * spafac * 1.8; } else { #if 1 x += min + 4; xmax += min + 4; #else /*fixme:should calculate the space according to the last symbol duration */ x += (min + 4) * spafac; xmax += (min + 4) * spafac * 1.8; #endif } break; } } /* calculate the exact glue */ if (x >= width) { beta = 0; if (x == xmin) { alfa = 1; // no extra space } else { alfa = (x - width) / (x - xmin); /* shrink */ if (alfa > 1) { error(1, s, "Line too much shrunk (%.0f/%0.fpt of %.0fpt)", xmin, x, width); // uncomment for staff greater than music line // alfa = 1; } } realwidth = xmin * alfa + x * (1 - alfa); } else { alfa = 0; if (xmax > x) beta = (width - x) / (xmax - x); /* stretch */ else beta = 1; /* (no note) */ if (beta > beta0) { if (!cfmt.stretchstaff) beta = 0; } realwidth = xmax * beta + x * (1 - beta); } /* set the final x offsets */ s = tsfirst; if (alfa != 0) { if (alfa < 1) { x = xmin = 0; for (; s; s = s->ts_next) { if (s->sflags & S_SEQST) { xmin += s->shrink * alfa; x = xmin + s->x * (1 - alfa); } s->x = x; } } else { alfa = realwidth / x; x = 0; for (; s; s = s->ts_next) { if (s->sflags & S_SEQST) x = s->x * alfa; s->x = x; } } } else { x = 0; for (; s; s = s->ts_next) { if (s->sflags & S_SEQST) x = s->xmax * beta + s->x * (1 - beta); s->x = x; } } /* set the x offsets of the grace notes */ if (some_grace) { for (s = tsfirst; s; s = s->ts_next) { struct SYMBOL *g; if (s->type != GRACE) continue; x = s->x - s->wl + (cfmt.gracespace >> 16) * 0.1; for (g = s->extra; g; g = g->next) if (g->type == NOTEREST) g->x += x; } } } /* -- initialize a new music line -- */ static void new_music_line(void) { struct VOICE_S *p_voice; struct SYMBOL *s; int voice; /* set the first symbol of each voice */ tsfirst->ts_prev = NULL; for (p_voice = first_voice; p_voice; p_voice = p_voice->next) { p_voice->sym = NULL; /* may have no symbol */ voice = p_voice - voice_tb; for (s = tsfirst; s; s = s->ts_next) { if (s->voice == voice) { p_voice->sym = s; s->prev = NULL; break; } } } } /* -- initialize the start of generation / new music line -- */ static void gen_init(void) { struct SYMBOL *s; for (s = tsfirst ; s; s = s->ts_next) { if (s->extra) { output_ps(s, 0); if (!s->extra && s->type == FMTCHG) { unlksym(s); if (!tsfirst) return; } } if (s->sflags & S_NEW_SY) { s->sflags &= ~S_NEW_SY; cursys = cursys->next; } switch (s->type) { case CLEF: case KEYSIG: case TIMESIG: continue; // default: // break; /* may be Q: */ } return; } tsfirst = NULL; /* no more notes */ } /* -- show the errors -- */ static void error_show(void) { struct SYMBOL *s; for (s = tsfirst; s; s = s->ts_next) { if (s->flags & ABC_F_ERROR) { putxy(s->x, staff_tb[s->staff].y + s->y); a2b("showerror\n"); } } } /* -- delay output until the staves are defined (by draw_systems) -- */ static float delayed_output(float indent) { float line_height; char *outbuf_sav, *mbf_sav, *tmpbuf; outbuf_sav = outbuf; mbf_sav = mbf; tmpbuf = malloc(outbufsz); if (!tmpbuf) { error(1, NULL, "Out of memory for delayed outbuf - abort"); exit(EXIT_FAILURE); } mbf = outbuf = tmpbuf; *outbuf = '\0'; outft = -1; draw_sym_near(); outbuf = outbuf_sav; mbf = mbf_sav; outft = -1; line_height = draw_systems(indent); a2b("%s", tmpbuf); free(tmpbuf); return line_height; } /* -- generate the music -- */ void output_music(void) { struct VOICE_S *p_voice; float lwidth, indent; /* set the staff system if any STAVES at start of the next line */ gen_init(); if (!tsfirst) return; check_buffer(); set_global(); /* initialize the generator */ if (first_voice->next) { /* if many voices */ // if (cfmt.combinevoices >= 0) combine_voices(); set_stem_dir(); /* set the stems direction in 'multi' */ } for (p_voice = first_voice; p_voice; p_voice = p_voice->next) set_beams(p_voice->sym); /* decide on beams */ set_stems(); /* set the stem lengths */ if (first_voice->next) { /* when multi-voices */ set_rest_offset(); /* set the vertical offset of rests */ set_overlap(); /* shift the notes on voice overlap */ } set_acc_shft(); // set the horizontal offset of accidentals set_allsymwidth(NULL); /* set the width of all symbols */ lwidth = ((cfmt.landscape ? cfmt.pageheight : cfmt.pagewidth) - cfmt.leftmargin - cfmt.rightmargin) / cfmt.scale; if (lwidth < 50) { error(1, 0, "Bad page width %.1f", lwidth); lwidth = 10 CM; } indent = set_indent(); cut_tune(lwidth, indent); beta_last = 0; for (;;) { /* loop per music line */ float line_height; set_piece(); indent = set_indent(); set_sym_glue(lwidth - indent); if (indent != 0) a2b("%.2f 0 T\n", indent); /* do indentation */ line_height = delayed_output(indent); draw_all_symb(); draw_all_deco(); if (showerror) error_show(); bskip(line_height); if (indent != 0) { a2b("%.2f 0 T\n", -indent); insert_meter &= ~2; // no more indentation } tsfirst = tsnext; gen_init(); if (!tsfirst) break; buffer_eob(0); new_music_line(); } outft = -1; } /* -- reset the generator -- */ void reset_gen(void) { if (cfmt.fields[0] & (1 << ('M' - 'A'))) insert_meter = 3; /* insert meter and indent */ else insert_meter = 2; /* indent only */ }