/* * This file is part of jcabc2ps, * Copyright (C) 1996,1997,1998 Michael Methfessel * See file jcabc2ps.c for details. */ #include #include #include "jcabc2ps.h" #include "buffer.h" #include "parse.h" #include "subs.h" #include "util.h" #include "pssubs.h" #include "style.h" #include "text.h" #include "format.h" #include "playback.h" #include "music.h" /* subroutines connected with output of music */ /* ----- nwid ----- */ /* Sets the prefered width for a note depending on the duration. Return value is default space on right and left side. Function is determined by values at 0, 1/2, 1. Return value is 1.0 for quarter note. */ float nwid (float dur) { float a,b,x,p,x0,p0; a=2*(f1p-2*f5p+f0p); b=f1p-f0p-a; x = dur/(float)BASE; p = a*x*x + b*x + f0p; x0 = 0.25; p0 = a*x0*x0 + b*x0 + f0p; p = p/p0; return p; } /* ----- xwid -- --- */ /* same as nwid but for stretched system */ float xwid (float dur) { float a,b,x,p,x0,p0; a=2*(f1x-2*f5x+f0x); b=f1x-f0x-a; x = dur/(float)BASE; p = a*x*x + b*x + f0x; x0 = 0.25; p0 = a*x0*x0 + b*x0 + f0x; p = p/p0; return p; } /* ----- next_note, prec_note ------ */ int next_note (k,n,symb) int k,n; Sym symb[]; { int i; for (i=k+1;i=0;i--) { if ((symb[i].type == NOTE)||(symb[i].type == REST)) return i; } return -1; } /* ----- followed_by_note ------ */ int followed_by_note (k,n,symb) int k,n; Sym symb[]; { int i; for (i=k+1;i=0;i--) { switch (symb[i].type) { case INVISIBLE: break; case NOTE: case REST: return i; break; default: return -1; } } return -1; } void xch (i,j) /* sub to exchange two integers */ int *i,*j; { int k; k=*i; *i=*j; *j=k; } /* ----- print_linetype ----------- */ void print_linetype (t) int t; { if (t == COMMENT) fprintf(stderr,"COMMENT\n"); elsif (t == MUSIC) fprintf(stderr,"MUSIC\n"); elsif (t == TO_BE_CONTINUED) fprintf(stderr,"TO_BE_CONTINUED\n"); elsif (t == E_O_F) fprintf(stderr,"E_O_F\n"); elsif (t == INFO) fprintf(stderr,"INFO\n"); elsif (t == TITLE) fprintf(stderr,"TITLE\n"); elsif (t == METER) fprintf(stderr,"METER\n"); elsif (t == PARTS) fprintf(stderr,"PARTS\n"); elsif (t == KEY) fprintf(stderr,"KEY\n"); elsif (t == XREF) fprintf(stderr,"XREF\n"); elsif (t == DLEN) fprintf(stderr,"DLEN\n"); elsif (t == HISTORY) fprintf(stderr,"HISTORY\n"); elsif (t == TEMPO) fprintf(stderr,"TEMPO\n"); elsif (t == BLANK) fprintf(stderr,"BLANK\n"); elsif (t == VOICE) fprintf(stderr,"VOICE\n"); else fprintf(stderr,"UNKNOWN LINE TYPE\n"); } /* ----- print_syms: show sym properties set by parser ------ * This produces a dump of all the Syms. * Bug: Pitches need to be un-adjusted for clef and octave. * How can we find the right offset for each Sym? */ void print_syms(num1,num2,symb) int num1,num2; Sym symb[]; { char *F = "print_syms"; int a,i,t,j,y; char *acc; Ksig* ks; char dsym[21] = {' ','~','.','J','M','H','u','v','R','T','K'}; char bsym[10] = {'-', '1' ,'2', '3', '4', '5', '6', '7', '8', '9'}; char str[21]; fprintf(stderr,"\n---------- Symbol list ----------\n"); fprintf(stderr,"word slur eol num description\n"); for (i=num1;i1) fprintf(stderr," ["); for (j=0;j1) fprintf(stderr," ]"); if (symb[i].p_plet) fprintf(stderr," (%d:%d:%d", symb[i].p_plet,symb[i].q_plet,symb[i].r_plet); if (symb[i].ach[0]) fprintf(stderr," \"%s\"", symb[i].ach); if (symb[i].achp) fprintf(stderr," pos %d", symb[i].achp); if (symb[i].achy) fprintf(stderr," at %6.3f", symb[i].achy); if (symb[i].ann) { V7 "%s: symb %d has %d-byte annotation !%s!\n",F,i,symb[i].ann->l,TextStr(symb[i].ann) V; fprintf(stderr," !%s!", symb[i].ann->t); fprintf(stderr," pos %d", symb[i].ann->p); fprintf(stderr," at %6.3f", symb[i].ann->y); } if (symb[i].dc.n>0) { fprintf(stderr," deco "); for (j=0;j0) { fprintf(stderr," grace "); for (j=0;j0) fprintf(stderr,"-"); if (symb[i].gr.a[j] == A_SH) fprintf(stderr,"^"); if (symb[i].gr.a[j] == A_HSH) fprintf(stderr,"^/"); if (symb[i].gr.a[j] == A_NT) fprintf(stderr,"="); if (symb[i].gr.a[j] == A_FT) fprintf(stderr,"_"); if (symb[i].gr.a[j] == A_HFT) fprintf(stderr,"_/"); symbolic_pitch (symb[i].gr.p[j],str); fprintf(stderr,"%s",str); } } break; case BAR: fprintf(stderr,"BAR == == == = "); if (symb[i].u == B_SNGL) fprintf(stderr,"single"); if (symb[i].u == B_DBL) fprintf(stderr,"double"); if (symb[i].u == B_LREP) fprintf(stderr,"left repeat %d",symb[i].lrep); if (symb[i].u == B_RREP) fprintf(stderr,"right repeat %d",symb[i].rrep); if (symb[i].u == B_DREP) fprintf(stderr,"double repeat %d/%d",symb[i].lrep,symb[i].rrep); if (symb[i].u == B_FAT1) fprintf(stderr,"thick-thin"); if (symb[i].u == B_FAT2) fprintf(stderr,"thin-thick"); if (symb[i].u == B_FAT3) fprintf(stderr,"thin-thick-thin"); if (symb[i].u == B_INVIS) fprintf(stderr,"invisible"); if (symb[i].v) fprintf(stderr,", ending %d", symb[i].v); if (symb[i].ach[0]) fprintf(stderr,", achord \"%s\"",symb[i].ach); if (symb[i].achy) fprintf(stderr," at %6.3f", symb[i].achy); if (symb[i].ann) { fprintf(stderr,", annot !%s!", symb[i].ann->t); fprintf(stderr," pos %d", symb[i].ann->p); fprintf(stderr," at %6.3f", symb[i].ann->y); } if (symb[i].gr.n>0) { fprintf(stderr," grace "); for (j=0;j0) fprintf(stderr,"-"); if (symb[i].gr.a[j] == A_SH) fprintf(stderr,"^"); if (symb[i].gr.a[j] == A_HSH) fprintf(stderr,"^/"); if (symb[i].gr.a[j] == A_NT) fprintf(stderr,"="); if (symb[i].gr.a[j] == A_FT) fprintf(stderr,"_"); if (symb[i].gr.a[j] == A_HFT) fprintf(stderr,"_/"); symbolic_pitch (symb[i].gr.p[j],str); fprintf(stderr,"%s",str); } } break; case CLEF: switch (symb[i].u) { case NOCLEF: fprintf(stderr,"CLEF NOCLEF"); break; case NOCLEFd8: fprintf(stderr,"CLEF NOCLEF-8"); break; case NOCLEFu8: fprintf(stderr,"CLEF NOCLEF+8"); break; case TREBLE: fprintf(stderr,"CLEF TREBLE"); break; case TREBLEd8: fprintf(stderr,"CLEF TREBLE-8"); break; case TREBLEu8: fprintf(stderr,"CLEF TREBLE+8"); break; case TENOR: fprintf(stderr,"CLEF TENOR"); break; case ALTO: fprintf(stderr,"CLEF ALTO"); break; case ALTOd8: fprintf(stderr,"CLEF ALTO-8"); break; case ALTOu8: fprintf(stderr,"CLEF ALTO+8"); break; case BASS: fprintf(stderr,"CLEF BASS"); break; case BASSd8: fprintf(stderr,"CLEF BASS-8"); break; case BASSu8: fprintf(stderr,"CLEF BASS+8"); break; default: fprintf(stderr,"CLEF=%d unknown",t); break; } break; case TIMESIG: fprintf(stderr,"TIMESIG "); if (symb[i].w == 1) fprintf(stderr,"C"); elsif (symb[i].w == 2) fprintf(stderr,"C|"); else fprintf(stderr,"%d/%d", symb[i].u,symb[i].v); break; case KEYSIG: fprintf(stderr,"KEYSIG "); if (symb[i].t == A_SH) fprintf(stderr,"sharps "); if (symb[i].t == A_HSH) fprintf(stderr,"halfsharps "); if (symb[i].t == A_FT) fprintf(stderr,"flats "); if (symb[i].t == A_HFT) fprintf(stderr,"halfflats "); if (symb[i].t == A_MX) fprintf(stderr,"mixed "); if (ks = symb[i].ksig) { fprintf(stderr," K:"); for (a=0; adata.accs; a++) { acc = (ks->data.atyp[a] == A_SH) ? "^" : (ks->data.atyp[a] == A_HSH) ? "^/" : (ks->data.atyp[a] == A_FT) ? "_" : (ks->data.atyp[a] == A_HFT) ? "_/" : (ks->data.atyp[a] == A_NT) ? "=" : "?"; fprintf(stderr,"%s%c",acc,ks->data.aval[a]); } } fprintf(stderr," q=%d t=%d u=%d v=%d w=%d acc1=%d acc2=%d" ,symb[i].q,symb[i].t,symb[i].u,symb[i].v,symb[i].w,symb[i].acc1,symb[i].acc2); if (symb[i].acc2 < symb[i].acc1) fprintf(stderr,", neutrals from %d", symb[i].acc2); break; case INVISIBLE: fprintf(stderr,"INVIS "); break; default: fprintf(stderr,"UNKNOWN "); break; } fprintf(stderr,"\n"); } fprintf(stderr,"\n"); } /* ----- print_vsyms: print symbols for all voices ----- */ void print_vsyms () { char *F = "print_vsyms"; int v, s; fprintf(stderr,"\n"); for (v = 0; v < nvoice; v++) { // if (nvoice>1) fprintf(stderr,"Voice <%s> (%d of %d)", voice[v].id,v,nvoice); print_syms(0,voice[v].nsym,symv[v]); } } /* ----- set_head_directions ----------- */ /* decide whether to shift heads to other side of stem on chords */ /* also position accidentals to avoid too much overlap */ void set_head_directions (s) Sym *s; { int i,n,nx,sig,d,da,shift,nac; int i1,i2,m; float dx,xx,xmn; n=s->npitch; sig=-1; if (s->stem>0) sig=1; for (i=0;ishhd[i]=0; s->shac[i]=8; if (s->head == H_OVAL) s->shac[i]+=3; s->xmn=0; s->xmx=0; } if (n<2) return; /* sort heads by pitch */ for (;;) { nx=0; for (i=1;ivpos[i] - s->vpos[i-1]) * sig > 0) { xch(&s->pits[i],&s->pits[i-1]); xch(&s->vpos[i],&s->vpos[i-1]); xch(&s->lens[i],&s->lens[i-1]); xch(&s->accs[i],&s->accs[i-1]); xch(&s->sl1[i],&s->sl1[i-1]); xch(&s->sl2[i],&s->sl2[i-1]); xch(&s->ti1[i],&s->ti1[i-1]); xch(&s->ti2[i],&s->ti2[i-1]); nx++; } } if (!nx) break; } shift=0; /* shift heads */ for (i=n-2;i>=0;i--) { d = s->vpos[i+1] - s->vpos[i]; if (d<0) d=-d; if ((d>=2) || (d == 0)) shift=0; else { shift=1-shift; if (shift) { dx=7.8; if (s->head == H_EMPTY) dx=7.8; if (s->head == H_OVAL) dx=10.0; if (s->stem == -1) s->shhd[i]=-dx; else s->shhd[i]=dx; } } if (s->shhd[i] < s->xmn) s->xmn = s->shhd[i]; if (s->shhd[i] > s->xmx) s->xmx = s->shhd[i]; } shift=0; /* shift accidentals */ i1=0; i2=n-1; if (sig<0) { i1=n-1; i2=0; } for (i=i1; ; i=i+sig) { /* count down in terms of pitch */ xmn=0; /* left-most pos of a close head */ nac=99; /* relative pos of next acc above */ for (m=0; mshhd[m]; d = s->vpos[m] - s->vpos[i]; da=ABS(d); if ((da<=5) && (s->shhd[m]shhd[m]; if ((d>0) && (daaccs[m]) nac=da; } s->shac[i]=8.5-xmn+s->shhd[i]; /* aligns accidentals in column */ if (s->head == H_EMPTY) s->shac[i] += 1.0; if (s->head == H_OVAL) s->shac[i] += 3.0; if (s->accs[i]) { if (nac>=6) /* no overlap */ shift=0; elsif (nac>=4) { /* weak overlap */ if (shift == 0) shift=1; else shift=shift-1; } else { /* strong overlap */ if (shift == 0) shift=2; elsif (shift == 1) shift=3; elsif (shift == 2) shift=1; elsif (shift == 3) shift=0; } while (shift>=4) shift -=4; s->shac[i] += 3*shift; } if (i == i2) break; } } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * set_minsyms: want at least one symbol in each voice */ void set_minsyms(ivc) int ivc; { char*F="set_minsyms"; int n2; n2 = voice[ivc].nsym; // Last sym in voice V3 "%s: n2=%d\n",F,n2 V; if (n2>0) return; // There's alredy one sym? zeroSym(&symv[ivc][n2],"symv/set_minsyms"); symv[ivc][n2].type = INVISIBLE; symv[ivc][n2].u = 3; symv[ivc][n2].v = 3; symv[ivc][n2].w = 3; voice[ivc].nsym++; // Count the invisible sym } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * setSymChrs: set symbol characteristics */ void setSymChrs (n1,n2,sp) int n1,n2; Sym *sp; { char *F="setSymChrs"; int i,np,m,ymn,ymx; float yav,yy; for (i=n1;i ymx) ymx = yy; } sp[i].ymn=ymn; sp[i].ymx=ymx; sp[i].yav=yav; sp[i].ylo=ymn; sp[i].yhi=ymx; } } } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * set_beams: decide on beams */ void set_beams (n1,n2,symb) int n1,n2; Sym symb[]; { int j,lastnote,start_flag; /* separate words at notes without flags */ start_flag=0; lastnote=-1; for (j=n1;j=0) symb[lastnote].word_end=1; symb[j].word_st=1; symb[j].word_end=1; start_flag=1; } lastnote=j; } } } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * setStem: set stem directions and lengths. * This is really just a debug wrapper around the assignment, * though other stem-related code may be moved here eventually. */ void setStem(n,sp,dir,C) int n; /* Symbol number */ Sym* sp; /* Add stem to this symbol */ int dir; /* 1=up -1=down */ char*C; /* Caller's name */ { char*F="setStem"; unless (sp) {V1 "%s: Called by %s with sp null!!!\n",F,C V; return;} sp->stem = dir; V5 "%s: Stem of symbol %d is %d.\n",C,n,dir V; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * setStems: decide on stem directions and lengths */ void setStems (n1,n2,symb) int n1,n2; Sym symb[]; { char *F="setStems"; int beam,j,k,n,stem,laststem; float avg,slen,lasty,dy; /* set stem directions; near middle, use previous direction */ beam=0; laststem=0; for (j=n1; j= 12) setStem(j, &symb[j], -symb[j].stem, F); if ((symb[j].yav > 11) && (symb[j].yav < 13) && (laststem != 0)) { dy=symb[j].yav-lasty; if ((dy>-7) && (dy<7)) setStem(j, &symb[j], laststem, F); } if (symb[j].word_st && (!symb[j].word_end)) { /* start of beam */ avg=0; n=0; for (k=j;k= 12) stem = -1; if ((avg > 11) && (avg < 13) && (laststem != 0)) stem = laststem; beam = 1; } if (beam) setStem(j, &symb[j], stem, F); if (symb[j].word_end) beam = 0; if (bagpipe) setStem(j, &symb[j], -1, F); if (symb[j].len>=WHOLE) setStem(j, &symb[j], 0, F); laststem = symb[j].stem; if (symb[j].len >= HALF) laststem = 0; lasty = symb[j].yav; } else { laststem = 0; } } /* shift notes in chords (need stem direction to do this) */ for (j=n1;j1) slen = STEM_CH; if (symb[j].flags == 3) slen += 4; if (symb[j].flags == 4) slen += 9; if ((symb[j].flags>2) && (symb[j].stem == 1)) slen -= 1; if (symb[j].stem == 1) { symb[j].y = symb[j].ymn; symb[j].ys = symb[j].ymx+slen; } elsif (symb[j].stem == -1) { symb[j].y = symb[j].ymx; symb[j].ys = symb[j].ymn-slen; } else { symb[j].y = symb[j].ymx; symb[j].ys = symb[j].ymx; } } } /* ----- set_sym_times: set time axis; also count through bars ----- */ int set_sym_times(n1,n2,symb,meter0) int n1,n2; Sym symb[]; Msig meter0; { char *F = "set_sym_times"; int i,pp,qq,rr,meter1,meter2,count,bnum,lastb,bsave; int qtab[] = {0,0,3,2,3,0,2,0,3,0}; float time, factor, fullmes; meter1 = meter0.meter1; meter2 = meter0.meter2; V3 "%s: meter1=%d meter2=%d.\n",F,meter1,meter2 V; lastb=bnum=0; bsave=1; time=0.0; factor=1.0; for (i=n1;i=fullmes-0.001) { bnum++; while (symb[i+1].type == BAR) {i++; symb[i].time=time; } symb[i].t = bnum; lastb = i; } if (symb[i].v > 1) { bnum = bsave; symb[i].t = 0; } if (symb[i].v == 1) bsave=bnum; } if ((symb[i].type == NOTE)||(symb[i].type == REST)) { if (symb[i].p_plet) { pp=symb[i].p_plet; qq=symb[i].q_plet; rr=symb[i].r_plet; if (qq == 0) { qq=qtab[pp]; if (qq == 0) { qq=2; if (meter1 % 3 == 0) qq = 3; } } factor=((float)qq)/((float)pp); count=rr; } time=time+factor*symb[i].len; if (count>0) count--; if (count == 0) factor=1; } if (symb[i].type == TIMESIG) { /* maintain meter as we go along */ meter1 = symb[i].u; meter2 = symb[i].v; V3 "%s: TIMESIG symb[%d] meter1=u=%d meter2=v=%d.\n",F,meter1,meter2 V; } } return bnum; } /* ----- setSymWidths: set widths and prefered space --- */ /* 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. It also sets the prefered spacings pl,pr for good output and xl,xr for expanded layout. All distances in pt relative to the symbol center. */ void setSymWidths (ns1,ns2,symb,ivc) int ns1,ns2,ivc; Sym symb[]; { char *F = "setSymWidths"; int i,n,j0,j,m,n1,n2,bt,k,st,sl,k1,k2,got_note,ok,wr; float xx,w,swfac,spc,dur,yy; char t[81],tt[81]; V6 "%s: Called with ns1=%d ns2=%d symb[%d]\n",F,ns1,ns2,ivc V; swfac = 1.0; if (strstr(cfmt.vocalfont.name,"Times-Roman")) swfac=1.00; if (strstr(cfmt.vocalfont.name,"Times-Courier")) swfac=1.05; if (strstr(cfmt.vocalfont.name,"Helvetica")) swfac=1.00; if (strstr(cfmt.vocalfont.name,"Helvetica-Bold")) swfac=1.05; got_note = 0; for (i=ns1; i0) { xx=GSPACE0; if (symb[i].gr.a[0]) xx=xx+3.5; for (j=1;j0) AT_LEAST (symb[i].wr, 12); /* leave room for dots */ if (symb[i].dots>0) { AT_LEAST (symb[i].wr,12+symb[i].xmx); if (symb[i].dots>=2) symb[i].wr=symb[i].wr+3.5; n = (int) symb[i].y; /* special case: standalone with up-stem and flags */ if (symb[i].flags && (symb[i].stem == 1) && !(n%6)) { if ((symb[i].word_st == 1) && (symb[i].word_end == 1)) { symb[i].wr = symb[i].wr + DOTSHIFT; symb[i].pr = symb[i].pr + DOTSHIFT; symb[i].xr = symb[i].xr + DOTSHIFT; } } } /* extra space when down stem follows up stem */ j0=preceded_by_note(i,ns2,symb); if ((j0>=0) && (symb[j0].stem == 1) && (symb[i].stem == -1)) AT_LEAST (symb[i].wl, 7); /* make sure helper lines don't overlap */ if ((j0>=0) && (symb[i].y>27) && (symb[j0].y>27)) AT_LEAST (symb[i].wl, 7.5); /* leave room accompaniment chord */ if (strlen(symb[i].ach)>0) { /* * Special case: accomp chord under ending. Leave some room * to the left of the note. Adjust for length of ending achord [jc] */ V3 "%s: symb %d chord \"%s\" under ending %d (%s)\n" ,F,i,symb[i].ach,symb[i-1].v,symb[i].vtxt V; if ((i>0) && (symb[i-1].type == BAR)) { V3 "%s: BAR sym %d.\n",F,i V; if (bt = symb[i-1].v) { wr = 8 * strlen(symb[i-1].vtxt); V3 "%s: BAR sym %d bt=%d wr=%d.",F,i-1,bt,wr V; if (bt) AT_LEAST(symb[i].wl,wr); V3 "%s: symb[%d].vtxt=\"%s\" u=%d wr=%d.\n" ,F,i,symb[i].vtxt,symb[i].u,symb[i].wr V; } } #if 0 V6 "%s: symb[%d].vtxt=\"%s\" u=%d wr=%d.\n" ,F,i,symb[i].vtxt,symb[i].u,symb[i].wr V; if (*symb[i].vtxt) { symb[i].wr += strlen(symb[i].vtxt); V3 "%s: symb[%d].vtxt=\"%s\" u=%d wr=%d.\n" ,F,i,symb[i].vtxt,symb[i].u,symb[i].wr V; } #endif /* rest is same for all accomp chord cases */ tex_str(symb[i].ach,t,&w); xx=cfmt.achordfont.size*w; xx=xx*1.05; /* extra space mainly for helvetica font */ spc=xx*GCHPRE; k1=prec_note(i,ns2,symb); k2=next_note(i,ns2,symb); if (spc>8.0) spc=8.0; if ((k1) && (strlen(symb[k1].ach)>0)) AT_LEAST (symb[i].wl, spc); if ((k2>0) && (strlen(symb[k2].ach)>0)) AT_LEAST (symb[i].wr, xx-spc); } /* leave room annotation */ if (symb[i].ann) { /* * Special case: annotations under ending. Leave some room * to the left of the note. Adjust for length of ending text [jc] */ V3 "%s: symb %d annotation \"%s\" under ending %d (%s)\n" ,F,i,symb[i].ann->t,symb[i-1].v,symb[i].vtxt V; if ((i>0) && (symb[i-1].type == BAR)) { V3 "%s: BAR sym %d.\n",F,i V; if (bt = symb[i-1].v) { wr = 8 * strlen(symb[i-1].vtxt); V3 "%s: BAR sym %d bt=%d wr=%d.",F,i-1,bt,wr V; if (bt) AT_LEAST(symb[i].wl,wr); V3 "%s: symb[%d].vtxt=\"%s\" u=%d wr=%d.\n" ,F,i,symb[i].vtxt,symb[i].u,symb[i].wr V; } } #if 0 V6 "%s: symb[%d].vtxt=\"%s\" u=%d wr=%d.\n" ,F,i,symb[i].vtxt,symb[i].u,symb[i].wr V; if (*symb[i].vtxt) { symb[i].wr += strlen(symb[i].vtxt); V3 "%s: symb[%d].vtxt=\"%s\" u=%d wr=%d.\n" ,F,i,symb[i].vtxt,symb[i].u,symb[i].wr V; } #endif /* rest is same for all annotation cases */ tex_str(symb[i].ann->t,t,&w); xx=cfmt.annotfont.size*w; xx=xx*1.05; /* extra space mainly for helvetica font */ spc=xx*GCHPRE; k1=prec_note(i,ns2,symb); k2=next_note(i,ns2,symb); if (spc>8.0) spc=8.0; if (symb[k1].ann) { if ((k1>0) && symb[k1].ann && symb[k1].ann->t) AT_LEAST (symb[i].wl, spc); if ((k2>0) && symb[k2].ann && symb[k2].ann->t) AT_LEAST (symb[i].wr, xx-spc); } } /* leave room for vocals under note */ for (j=0;j0) && (symb[i].t%cfmt.barnums == 0)) { ok=1; } if (strlen(symb[i].ach)>0) ok=1; if (symb[i].ann) ok=1; if (ok) { if (strlen(symb[i].ach)>0) { tex_str(symb[i].ach,t,&w); xx=cfmt.barlabelfont.size*w*0.5; } elsif (symb[i].ann) { tex_str(symb[i].ann->t,t,&w); xx=cfmt.barlabelfont.size*w*0.5; } else { sprintf (tt,"%d",symb[i].t); tex_str(tt,t,&w); xx=cfmt.barnumfont.size*w*0.5; } yy=60; if (!got_note) yy=0; if (symb[i-1].type == NOTE) { yy=symb[i-1].ymx; if (symb[i-1].stem == 1) yy=yy+26; } if (strlen(symb[i-1].ach)>0) yy=60; if (symb[i-1].ann) yy=60; AT_LEAST (symb[i].wl, 2); if (yy>BNUMHT-4.0) AT_LEAST (symb[i].wl, xx+1); if (!got_note) AT_LEAST (symb[i].wl, xx+1); yy=0; if (symb[i+1].type == NOTE) yy=symb[i+1].ymx; if (yy>BNUMHT-4.0) AT_LEAST (symb[i].wr, xx+2); if (strlen(symb[i+1].ach)>0) AT_LEAST (symb[i].wr, xx+4); if (symb[i+1].ann) AT_LEAST (symb[i].wr, xx+4); } } symb[i].pl = symb[i].wl; symb[i].pr = symb[i].wr; symb[i].xl = symb[i].wl; symb[i].xr = symb[i].wr; break; case CLEF: /* V5 "%s: CLEF Sym %d has u=%d v=%d w=%d t=%d q=%d clef=%d acc1=%d acc2=%d.\n",F, i,symb[i].u,symb[i].v,symb[i].w,symb[i].t,symb[i].q,symb[i].clef,symb[i].acc1,symb[i].acc2 V; switch (symb[i].u) { // Clef widths constant except for "none" case NOCLEF: symb[i].wl = symb[i].wr = symb[i].xl = 0; symb[i].pl = symb[i].pr = symb[i].xr = 0; break; default: symb[i].wl = symb[i].wr = symb[i].xl = 9.5; symb[i].pl = symb[i].pr = symb[i].xr = 9.5; } */ V5 "%s: CLEF Sym %d has u=%d v=%d w=%d t=%d q=%d clef=%d acc1=%d acc2=%d.\n",F, i,symb[i].u,symb[i].v,symb[i].w,symb[i].t,symb[i].q,symb[i].clef,symb[i].acc1,symb[i].acc2 V; switch (symb[i].u) { // Clef widths constant except for "none" case NOCLEF: symb[i].wl = symb[i].wr = symb[i].xl = 0; symb[i].pl = symb[i].pr = symb[i].xr = 0; break; default: symb[i].wl = symb[i].wr = symb[i].xl = 13.5; symb[i].pl = symb[i].pr = symb[i].xr = 11.5; symb[i].pl = symb[i].wl = symb[i].xl = 7.0; // [jc] Shifted clefs left to edge of staff } break; case KEYSIG: V6 "%s: KEYSIG Sym %d has u=%d v=%d w=%d t=%d q=%d clef=%d acc1=%d acc2=%d.\n",F, i,symb[i].u,symb[i].v,symb[i].w,symb[i].t,symb[i].q,symb[i].clef,symb[i].acc1,symb[i].acc2 V; n1 = symb[i].u >= 0 ? symb[i].u : symb[i].clef; n2 = symb[i].v >= 0 ? symb[i].v : symb[i].acc1; if (symb[i].ksig) { V6 "%s: KEYSIG %s.\n",F,dmpKsig(symb[i].ksig) V; V6 "%s: KEYSIG accs=%d.\n",F,symb[i].ksig->data.accs V; } else { V6 "%s: KEYSIG no ksig field.\n",F V; } if (n2>=n1) { V6 "%s: KEYSIG Sym %d n2=%3.1f >= n1=%3.1f.\n",F,i,n2,n1 V; symb[i].wl = 5; /* Was 2 [jc] */ symb[i].wr = 6*(n2-n1+1)-2; /* Was +2 [jc] */ symb[i].pl = symb[i].wl; symb[i].pr = symb[i].wr; symb[i].xl = symb[i].wl; symb[i].xr = symb[i].wr; } else { V6 "%s: KEYSIG Sym %d n2=%3.1f < n1=%3.1f.\n",F,i,n2,n1 V; symb[i].wl = symb[i].pl = symb[i].xl = 1; /* Was 3 [jc] */ symb[i].wr = symb[i].pr = symb[i].xr = 0; /* Was 3 [jc] */ } V6 "%s: KEYSIG Sym %d set pl=%3.1f pr=%3.1f.\n",F,i,symb[i].pl,symb[i].pr V; V6 "%s: KEYSIG Sym %d set wl=%3.1f wr=%3.1f.\n",F,i,symb[i].wl,symb[i].wr V; V6 "%s: KEYSIG Sym %d set xl=%3.1f xr=%3.1f.\n",F,i,symb[i].xl,symb[i].xr V; break; case TIMESIG: V3 "%s: TIMESIG u=%d v=%d w=%d.\n",F,symb[i].u,symb[i].v,symb[i].w V; switch (symb[i].w) { case 4: // Free meter. V3 "%s: TIMESIG (none)\n",F V; symb[i].wl = 0.0; symb[i].wr = 0.0; symb[i].pl = 0.0; symb[i].pr = 0.0; symb[i].xl = 0.0; symb[i].xr = 0.0; break; default: V3 "%s: TIMESIG %d/%d\n",F,symb[i].u,symb[i].v V; symb[i].wl = 6+4*(strlen(symb[i].ach)-1); // Was 8+4*... symb[i].wr = symb[i].wl; // Was +4; symb[i].pl = symb[i].wl; symb[i].pr = symb[i].wr; symb[i].xl = symb[i].wl; symb[i].xr = symb[i].wr; break; } V3 "%s: TIMESIG symb[%d] wl=%6.3f pl=%6.3f xl=%6.3f.\n",F,i,symb[i].wl,symb[i].pl,symb[i].xl V; V3 "%s: TIMESIG symb[%d] wr=%6.3f pr=%6.3f xr=%6.3f.\n",F,i,symb[i].wr,symb[i].pr,symb[i].xr V; break; default: fprintf(stderr,">>> cannot set width for sym type %d\n", symb[i].type); symb[i].wl = symb[i].wr = symb[i].xl = 0; symb[i].pl = symb[i].pr = symb[i].xr = 0; break; } } } /* ----- contract_ksigs: delete duplicate keysigs at staff start ---- * Depending on line breaks, a key and/or meter change can come * at the start of a staff. Solution: scan through symbols from start * of line as long as sym is a CLEF, KEYSIG, or TIMESIG. Remove all * these, but set flags so that set_initsyms will draw the * key and meter which result at the end of the scan. */ int contract_ksigs (ip1) int ip1; { char *F = "contract_ksigs"; int i,k,v,t,n3,sf,jp1,m,mtop,type; Ksig *ks; V6 "%s: Called with ip1=%d.\n",F,ip1 V; mtop = 10000; for (v=0; v=0) { type = symv[v][k].type; V6 "%s: Voice %d symv[%d][%d].type=%d=%s.\n",F,v,v,k,type,SymName(type) V; if (type == CLEF) { voice[v].key->data.clef = symv[v][k].u; symv[v][k].type=INVISIBLE; } elsif (type == KEYSIG) { V6 "%s: KEYSIG Sym[%d][%d] q=%d t=%d u=%d v=%d w=%d acc1=%d acc2=%d ksig=%X.\n", F,v,i,symv[v][k].q,symv[v][k].t,symv[v][k].u,symv[v][k].v,symv[v][k].w, symv[v][k].acc1,symv[v][k].acc2,symv[v][k].ksig V; sf = symv[v][k].v >= 0 ? symv[v][k].v : symv[v][k].acc1; n3 = symv[v][k].w >= 0 ? symv[v][k].w : symv[v][k].acc2; if (n3-1 < sf) { V6 "%s: Adjust sf from %d to %d.\n",F,sf,n3-1 V; sf = n3-1; } t = symv[v][k].t; if (t == A_FT) sf = -sf; if (t == A_NT) sf = 0; voice[v].key->data.sf = sf; if (ks = symv[v][k].ksig) { V6 "%s: Sym[%d][%d].ksig is %s\n",F,v,k,dmpKsig(ks) V; voice[v].key = asgnKsig(voice[v].key, ks); } V6 "%s: Sym[%d][%d] final sf is %d.\n",F,v,i,sf V; symv[v][k].type = INVISIBLE; symv[v][k].acc1 = sf; symv[v][k].acc2 = n3; } elsif (type == TIMESIG) { voice[v].meter.insert = 1; voice[v].meter.meter1 = symv[v][k].u; V3 "%s: voice[%d].meter.meter1 = symv[%d][%d].u = %d.\n",F,v,v,k,voice[v].meter.meter1 V; voice[v].meter.meter2 = symv[v][k].v; V3 "%s: voice[%d].meter.meter2 = symv[%d][%d].v = %d.\n",F,v,v,k,voice[v].meter.meter1 V; voice[v].meter.mflag = symv[v][k].w; V3 "%s: voice[%d].meter.mflag = symv[%d][%d].w = %d.\n",F,v,v,k,voice[v].meter.mflag V; strcpy(voice[v].meter.top,symv[v][k].ach); symv[v][k].type = INVISIBLE; } else { V6 "%s: Ignore type %d.\n",F,type V; break; } } else { V3 "%s: +++ k=%d = xp[%d].p[%d] +++\n",F,k,i,v V; } V6 "%s: Advance i from %d to %d.\n",F,i,xp[i].next V; i = xp[i].next; if (i == XP_END) { i = xp[i].prec; break; } } if (m < mtop && i >= 0) {mtop = m; jp1 = i; } } /* set glue for first symbol */ xp[jp1].shrink = xp[jp1].wl+3; xp[jp1].space = xp[jp1].wl+9; xp[jp1].stretch= xp[jp1].wl+16; return jp1; } /* ----- set_initsyms: set symbols at start of staff ----- */ int set_initsyms (v,wid0) int v; float *wid0; { char *F = "set_initsyms"; int a,k,t,n; float x; k = 0; /* add clef */ zeroSym(&sym_st[v][k],"sym_st/set_initsyms 1"); sym_st[v][k].type = CLEF; sym_st[v][k].u = voice[ivc].key->data.clef; sym_st[v][k].v = 0; k++; /* add keysig */ zeroSym(&sym_st[v][k],"sym_st/set_initsyms 2"); sym_st[v][k].type = KEYSIG; a = voice[ivc].key->data.accs; n = voice[ivc].key->data.sf; t = A_SH; if (n<0) { n = -n; t = A_FT; } sym_st[v][k].u = 1; sym_st[v][k].v = a ? a : n; sym_st[v][k].w = 100; sym_st[v][k].t = t; k++; /* add timesig */ if (voice[ivc].meter.insert) { zeroSym(&sym_st[v][k],"sym_st/set_initsyms 3"); sym_st[v][k].type = TIMESIG; sym_st[v][k].u = voice[ivc].meter.meter1; V5 "%s: sym_st[%d].u = voice[%d].meter.meter1 = %d.\n",F,v,ivc,sym_st[v][k].u V; sym_st[v][k].v = voice[ivc].meter.meter2; V5 "%s: sym_st[%d].v = voice[%d].meter.meter2 = %d.\n",F,v,ivc,sym_st[v][k].v V; sym_st[v][k].w = voice[ivc].meter.mflag; V5 "%s: sym_st[%d].2 = voice[%d].meter.mflag = %d.\n",F,v,ivc,sym_st[v][k].w V; strcpy(sym_st[v][k].ach,voice[ivc].meter.top); k++; voice[ivc].meter.insert=0; } if (voice[ivc].insert_btype) { sym_st[v][k].type = BAR; sym_st[v][k].u=voice[ivc].insert_btype; sym_st[v][k].v=voice[ivc].insert_num; sym_st[v][k].t=voice[ivc].insert_bnum; strcpy(sym_st[v][k].ach,voice[ivc].insert_text); voice[ivc].insert_btype=0; voice[ivc].insert_bnum=0; k++; } n = k; setSymWidths(0,n,sym_st[v],ivc); x = 0; for (k=0; k=0) fprintf(stderr," %2d",xp[i].p[vv]); else fprintf(stderr," -"); } fprintf(stderr,"\n"); i=xp[i].next; n++; if (i == XP_END) break; } } /* ----- insert_poslist: insert new element after element nins ----- */ int insert_poslist (nins) int nins; { int new,nxt,vv; new=ixpfree; ixpfree++; if (new>=XP_END) rxi("Too many symbols; use -maxs to increase limit, now ",maxSyms); nxt=xp[nins].next; xp[new].prec=nins; xp[new].next=nxt; xp[nins].next=new; xp[nxt].prec=new; for (vv=0;vvtim+tol) break; } if (nok>0) { n=nok; } else { n=insert_poslist (nins); xp[n].type=typ; xp[n].time=tim; xp[n].dur = xp[n].tfac = 0; xp[n].shrink = xp[n].space = xp[n].stretch = 0; xp[n].wl = xp[n].wr = 0; xp[n].eoln=0; } symv[v][i].p=n; xp[n].p[v]=i; } } } /*| print_poslist (); |*/ } /* ----- set_xpwid: set symbol widths and tfac in xp list ----- */ void set_xpwid() { int i,j,k,i1,i2,k1,k2,v,nsm; float fac,dy,ff,wv,wx; /* set all tfacs to 1.0 */ i=i1=xp[XP_START].next; for (;;) { xp[i].tfac=1.0; xp[i].wl=xp[i].wr=WIDTH_MIN; i2=i; i=xp[i].next; if (i == XP_END) break; } /* loop over voices. first voice last, assumed most important */ for (v=nvoice-1;v>=0;v--) { nsm=voice[v].nsym; /* first symbol and last symbol */ k1=symv[v][0].p; k2=symv[v][nsm-1].p; if (k1 == i1 && symv[v][0].wl>xp[k1].wl) xp[k1].wl=symv[v][0].wl; if (k2 == i2 && symv[v][nsm-1].wr>xp[k2].wr) xp[k2].wr=symv[v][nsm-1].wr; /* loop over symbol nn pairs */ for (i=1;i xp[k1].wr) xp[k1].wr = symv[v][j].wr; if (symv[v][i].wl > xp[k2].wl) xp[k2].wl = symv[v][i].wl; if (symv[v][j].type == NOTE && symv[v][i].type == NOTE) { fac=1.0; /* reduce distance under a beam */ if (symv[v][i].word_st == 0) fac=fac*fnnp; /* reduce distance for large jumps in pitch */ dy = symv[v][i].y - symv[v][j].y; if (dy<0) dy=-dy; ff=1-0.010*dy; if (ff<0.9) ff=0.9; fac=fac*ff; xp[k2].tfac=fac; } } } } /* check for all nn pairs in voice, in case some syms very wide */ for (v=nvoice-1;v>=0;v--) { nsm=voice[v].nsym; for (i=1;i=0) xp[i].shrink=xp[j].wr+xp[i].wl; else xp[i].shrink=xp[i].wl; xp[i].space=xp[i].stretch=xp[i].shrink; if (xp[i].type == NOTE) { if (typl == NOTE) { /* note after another note */ w1 = lnnp*nwid(xp[j].dur); w2 = lnnp*nwid(xp[i].dur); xp[i].space = bnnp*w1 + (1-bnnp)*0.5*(w1+w2); w1 = lnnx*xwid(xp[j].dur); w2 = lnnx*xwid(xp[i].dur); xp[i].stretch = bnnx*w1 + (1-bnnx)*0.5*(w1+w2); } else { /* note at start of bar */ w1 = lbnp*nwid(xp[i].dur); w0 = lbnp*nwid(vbnp); if (w0>w1) w0=w1; xp[i].space = bbnp*w1 + (1-bbnp)*w0 + xp[j].wr; if (xp[i].space<14.0) xp[i].space=14.0; w1 = lbnx*xwid(xp[i].dur); w0 = lbnx*xwid(vbnp); if (w0>w1) w0=w1; xp[i].stretch = bbnx*w1 + (1-bbnx)*w0 + xp[j].wr; if (xp[i].stretch<18.0) xp[i].stretch=18.0; if (xp[i].shrink<12.0) xp[i].shrink=12.0; } } else { /* some other symbol after note */ if (typl == NOTE) { w1 = lnbp*nwid(xp[j].dur); w0 = lnbp*nwid(vnbp); xp[i].space = bnbp*w1 + (1-bnbp)*w0 + xp[i].wl; if (xp[i].space<13.0) xp[i].space = 13.0; w1 = lnbx*xwid(xp[j].dur); w0 = lnbx*xwid(vnbx); xp[i].stretch = bnbx*w1 + (1-bnbx)*w0 + xp[i].wl; if (xp[i].stretch<17.0) xp[i].stretch = 17.0; } } /* multiply space and stretch by factors tfac */ xp[i].space = xp[i].space*xp[i].tfac; xp[i].stretch = xp[i].stretch*xp[i].tfac; /* make sure that shrink < space < stretch */ if (xp[i].space=11) print_poslist(); } /* ----- check_overflow: returns upper limit which fits on staff ------ */ int check_overflow (int ip1, int ip2, float width) { int i,jp2,lastcut,nbar,need_note; float space,shrink,stretch,alfa,alfa0; /* max shrink is alfa0 */ alfa0=ALFA_X; if (cfmt.continueall) alfa0=cfmt.maxshrink; if (gmode == G_SHRINK) alfa0=1.0; if (gmode == G_SPACE) alfa0=0.0; if (gmode == G_STRETCH) alfa0=1.0; jp2=ip2; space=shrink=stretch=0; lastcut=-1; nbar=0; need_note=1; i=ip1; for (;;) { space=space+xp[i].space; shrink=shrink+xp[i].shrink; stretch=stretch+xp[i].stretch; alfa=0; if (space>shrink) { alfa=(space-width)/(space-shrink); if (xp[i].type!=BAR) alfa=((space+8)-width)/(space-shrink); } if (alfa>alfa0) { if (!cfmt.continueall) { if (verbose<=3) fprintf(stderr,"\n"); fprintf(stderr,"+++ Overfull after %d bar%s in staff %d\n", nbar, nbar == 1 ? "" : "s", mline); } jp2=i; if (i == ip1) jp2=xp[i].next; if (lastcut>=0) jp2=xp[lastcut].next; break; } /* The need_note business is to cut at the first of consecutive bars */ if (xp[i].type == NOTE) need_note=0; if (xp[i].type == BAR && need_note == 0) {lastcut=i; need_note=1; nbar++; } if (xp[i].type == KEYSIG) lastcut=i; i=xp[i].next; if (i == ip2) break; } return jp2; } /* ----- set_glue --------- */ float set_glue (int ip1, int ip2, float width) { char *F = "set_glue"; int i,j; float space,shrink,stretch,alfa,beta,glue,w,x,d1,d2,w1; float alfa0,beta0; alfa0=ALFA_X; /* max shrink and stretch */ if (cfmt.continueall) alfa0=cfmt.maxshrink; if (gmode == G_SHRINK) alfa0=1.0; if (gmode == G_SPACE) alfa0=0.0; if (gmode == G_STRETCH) alfa0=1.0; beta0=BETA_X; if (cfmt.continueall) beta0=BETA_C; space=shrink=stretch=0; i=ip1; for (;;) { space=space+xp[i].space; shrink=shrink+xp[i].shrink; stretch=stretch+xp[i].stretch; j=i; i=xp[i].next; if (i == ip2) break; } /* add extra space if last symbol is not a bar */ if (xp[j].type!=BAR) { d1=d2=xp[j].wr+3; if (xp[j].type == NOTE) d2 = lnbp*nwid(xp[j].dur)+xp[j].wr; if (d2width) { alfa=99; if (space>shrink) alfa=(space-width)/(space-shrink); } else { beta=99; if (stretch>space) beta=(width-space)/(stretch-space); if (!cfmt.stretchstaff) beta=0; } if (gmode == G_SHRINK) { alfa=1; beta=0;} /* force minimal spacing */ if (gmode == G_STRETCH) { alfa=0; beta=1;} /* force stretched spacing */ if (gmode == G_SPACE) { alfa=beta=0; } /* force natural spacing */ /*| if (alfa>alfa0) { alfa=alfa0; beta=0; } |*/ if (beta>beta0) { if (!cfmt.continueall) { V3 "\n%s: +++ Underfull (%.0fpt of %.0fpt) in staff %d\n",F, (beta0*stretch+(1-beta0)*space)*cfmt.scale,cfmt.staffwidth,mline V; } alfa=0; if (!cfmt.stretchstaff) beta=0; if ((!cfmt.stretchlast) && (ip2 == XP_END)) { w1 = alfa_last * shrink + beta_last * stretch + (1 - alfa_last - beta_last) * space; if (w1=2) { if (alfa > 0) fprintf(stderr,"Shrink staff %.0f%%", 100*alfa); elsif (beta > 0) fprintf(stderr,"Stretch staff %.0f%%", 100*beta); else fprintf(stderr,"No shrink or stretch"); fprintf(stderr," to width %.0f (%.0f,%.0f,%.0f)\n",w,shrink,space,stretch); } /* now calculate the x positions */ x=0; i=ip1; for (;;) { glue=alfa*xp[i].shrink+beta*xp[i].stretch+(1-alfa-beta)*xp[i].space; x=x+glue; xp[i].x=x; if (verbose>22) fprintf(stderr,"pos[%d]: type=%d pos=%.2f\n", i,xp[i].type,x); i=xp[i].next; if (i == ip2) break; } alfa_last=alfa; beta_last=beta; return w; } /* ----- adjGroup: even out spacings for one group of notes --- */ /* Here we repeat the whole glue thing, in rudimentary form */ void adjGroup(i1,i2) int i1,i2; { int j; float dx,x,spa,shr,str,hp,hx,alfa,beta,dur1; dx=sym[i2].x-sym[i1].x; shr=sym[i1].wr+sym[i2].wl; for (j=i1+1;jspa) beta=(dx-spa)/(str-spa); else alfa=(dx-spa)/(shr-spa); x=sym[i1].x; for (j=i1+1;j<=i2;j++) { x=x+alfa*(sym[j-1].wr+sym[j].wl)+beta*hx+(1-alfa-beta)*hp; sym[j].x=x; } } /* ----- adjSpace: even out triplet spacings etc --- */ void adjSpace (n) int n; { int i,i1,count,beam,num; /* adjust the n-plets */ count=0; for (i=1;i0 && sym[i].len!=sym[i1].len) count=0; if (count == 1) adjGroup (i1,i); if (count>0) count--; } else count=0; } /* adjust beamed notes of equal duration */ beam=0; for (i=1;i2 && num<4) adjGroup (i1,i); } if (sym[i].word_end) beam=0; } else beam=0; } } /* ----- adjRests: position single rests in bar center */ void adjRests (n,v) int n,v; { int i,ok; for (i=2;i= 0) { sym[n]=symv[v][k]; sym[n].x=xp[i].x+wid0; n++; m++; } i=xp[i].next; if (i == ip2) break; } /* adjust things for more pretty output.. */ adjRests (n,v); if (mvoice>1) adjSpace (n); /* small random shifts make the output more human... */ for (i=1;iRANCUT) r=RANCUT; x=ranf(-r,r); sym[i].x=sym[i].x+x; } } return n; } /* ----- draw_timesig ------- */ void draw_timesig (float x, Sym s) { char *F = "draw_timesig"; switch (s.w) { // case 0: // V3 "%s: u=%d v=%d w=%d ignored.\n",F,s.u,s.v,s.w V; // break; case 4: /* No timesig */ V3 "%s: u=%d v=%d w=%d (none).\n",F,s.u,s.v,s.w V; V3 "%s: %.1f nsig\n", F, x V; PUT1("%.1f nsig\n", x) break; case 1: V3 "%s: %.1f csig\n", F, x V PUT1("%.1f csig\n", x) break; case 2: PUT1("%.1f ctsig\n", x) break; default: /* Two-part timesig */ V3 "%s: %.1f (%s) (%d) tsig\n", F, x, s.ach, s.v V; PUT3("%.1f (%s) (%d) tsig\n", x, s.ach, s.v) // PUT3("%.1f (%d) (%d) tsig\n", x, s.u, s.v) } } /* * Vertical position of accidentals. This seems to be set up with a difference * of 3 between notes, with E corresponding to a height of 0. */ int sh_pos[8]={0,24,15,27,18, 9,21,15}; /* f c g d A e B */ int ft_pos[8]={0,12,21, 9,18, 6,15, 3}; /* B e A d G c F */ /* ----- draw_ksig: return sf for this key ----- */ int draw_ksig( int sn, float x, Sym s) { char *F = "draw_ksig"; float p; int a, cl, i,n1,n2,n3,t,yad,sf, v; int accs = -1; Ksig *ks = 0; V6 "%s: Sym %d has q=%d t=%d u=%d v=%d w=%d acc1=%d acc2=%d clef=%d yadd=%d.\n", F,sn,s.q,s.t,s.u,s.v,s.w,s.acc1,s.acc2,s.clef,s.yadd V; n1 = s.u >= 0 ? s.u : s.clef; /* which symbol to start with */ n2 = s.v >= 0 ? s.v : s.acc1; /* up to which symbol to go */ n3 = s.w >= 0 ? s.w : s.acc2; /* draw neutrals instead starting from this one */ t = s.t; /* type of symbol: sharp, flat or mixed */ V6 "%s: n1=%d n2=%d n3=%d t=%d.\n",F,n1,n2,n3,t V; if (ks = s.ksig) { V6 "%s: Sym has ksig=%lX (%s).\n",F,ks,dmpKsig(ks) V; cl = ks->data.clef; } else { V3 "%s: Sym %d has no ksig.\n",F,sn V; cl = voice[ivc].key->data.clef; } V6 "%s: Clef %d=%s.\n",F,cl,SymClef(cl) V; yad = 0; /* Y-position adjustment */ switch (cl) { case BASS: case BASSd8: case BASSu8: yad = -6; break; case ALTO: case ALTOd8: case ALTOu8: yad = -3; break; } accs = voice[ivc].key->data.accs; V6 "%s: yad=%d accs=%d.\n",F,yad,accs V; if (!ks) { if (ks = voice[ivc].key) { V6 "%s: voice %d has %s\n",F,ivc,dmpKsig(ks) V; } } if (ks) { V6 "%s: Ksig has %d accidentals.\n",F,ks->data.accs V; for (a=0; adata.accs; a++) { V6 "%s: Accidental %d: atyp=%d aval='%c' apos=%d.\n", F,a,ks->data.atyp[a],ks->data.aval[a],ks->data.apos[a] V; } } if (n2>7) { fprintf(stderr,"+++ Keysig seems to have %d symbols ???\n", n2); return 0; } sf=0; if (!oldks || ks->data.accs > 0) { accs = ks->data.accs; V3 "%s: New keysig code with accs=%d.\n",F,accs V; p = x; for (a=0; adata.atyp[a],ks->data.apos[a],yad V; if (a>0) { v = ks->data.apos[a] - ks->data.apos[a-1]; // Vertical separation between accidentals V3 "%s: Acc %d p=%.1f apos=%d v=%d <--\n",F,a,p,ks->data.apos[a],v V; v = ABS(v); V3 "%s: Acc %d p=%.1f apos=%d v=%d <--\n",F,a,p,ks->data.apos[a],v V; if (v<12) { // Extra space if different accidentals are nearly the same pitch p += 2; V3 "%s: Acc %d p=%.1f apos=%d v=%d <<<\n",F,a,p,ks->data.apos[a],v V; } } switch (ks->data.atyp[a]) { case A_SH: V5 "%s: Accidental %d SH at %d.\n",F,a,ks->data.apos[a]+yad V; PUT2("%.1f %d sh0 ",p,ks->data.apos[a]+yad); break; case A_HSH: V5 "%s: Accidental %d HSH at %d.\n",F,a,ks->data.apos[a]+yad V; PUT2("%.1f %d hsh0 ",p,ks->data.apos[a]+yad); break; case A_NT: V5 "%s: Accidental %d NT at %d.\n",F,a,ks->data.apos[a]+yad V; PUT2("%.1f %d nt0 ",p,ks->data.apos[a]+yad); break; case A_FT: V5 "%s: Accidental %d FT at %d.\n",F,a,ks->data.apos[a]+yad V; PUT2("%.1f %d ft0 ",p,ks->data.apos[a]+yad); break; case A_HFT: V5 "%s: Accidental %d HFT at %d.\n",F,a,ks->data.apos[a]+yad V; PUT2("%.1f %d hft0 ",p,ks->data.apos[a]+yad); break; } sf++; p += 5; } } else { V3 "%s: Original diatonic keysig code with t=%d.\n",F,t V; if (t == A_SH) { p = x; V3 "%s: A_SH x=%3.1f\n",F,x V; for (i=n1;i<=n2;i++) { if (i>=n3) PUT2("%.1f %d nt0 ",p,sh_pos[i]+yad) else { sf++; PUT2("%.1f %d sh0 ",p,sh_pos[i]+yad) } p=p+5; } PUT0("\n") } elsif (t == A_HSH) { p = x; V3 "%s: A_HSH x=%3.1f\n",F,x V; for (i=n1;i<=n2;i++) { if (i>=n3) PUT2("%.1f %d nt0 ",p,sh_pos[i]+yad) else { sf++; PUT2("%.1f %d hsh0 ",p,sh_pos[i]+yad) } p=p+5; } PUT0("\n") } elsif (t == A_FT) { V3 "%s: A_FT x=%3.1f\n",F,x V; p = x; for (i=n1;i<=n2;i++) { if (i>=n3) PUT2("%.1f %d nt0 ", p, ft_pos[i]+yad) else { sf--; PUT2("%.1f %d ft0 ", p, ft_pos[i]+yad) } p=p+5; } PUT0("\n") } elsif (t == A_HFT) { V3 "%s: A_HFT x=%3.1f\n",F,x V; p = x; for (i=n1;i<=n2;i++) { if (i>=n3) PUT2("%.1f %d nt0 ", p, ft_pos[i]+yad) else { sf--; PUT2("%.1f %d hft0 ", p, ft_pos[i]+yad) } p=p+5; } PUT0("\n") } else { V3 "%s: t=%d x=%3.1f\n",F,t,x V; bug ("wrong type in draw_ksig", 0); } } V6 "%s: Return sf=%d.\n",F,sf V; return sf; } /* ----- drawBar ------- */ void drawBar( float x, // X-pos of bar line float w, // Space to left of bar float d, // Distance to previous sym Sym *sp) // Symbol { char *F="drawBar"; int n; float top, top2; V5 "%s: Called at x=%.2f sp->u=%d.\n",F,x,sp->u V; if (sp->gr.n > 0) { V5 "%s: BAR has %d grace notes.\n",F,sp->gr.n V; drawGraceNotes(x,w,d,sp); } if (sp->u == B_SNGL) /* draw the bar */ PUT1("%.1f bar\n", x) elsif (sp->u == B_DBL) PUT1("%.1f dbar\n", x) elsif (sp->u == B_LREP) { V6 "%s: Left repeat.\n",F V; if (sp->lrep < 1) { /* [jc] */ V3 "%s: ### sp->lrep = %d.\n",F,sp->lrep V; sp->lrep = 1; } V3 "%s: Left repeat %d times.\n",F,sp->lrep V; PUT2("%.1f fbar1 %.1f rdots\n", x, x+10) x += 10; for (n=1; nlrep; n++) { x += 6; PUT1("%.1f rdots\n", x) V3 "%s: Repeat %d.\n",F,n V; } } elsif (sp->u == B_RREP) { V6 "%s: Right repeat.\n",F V; if (sp->rrep < 1) { /* [jc] */ V3 "%s: ### sp->rrep = %d.\n",F,sp->rrep V; sp->rrep = 1; } V3 "%s: Left repeat %d times.\n",F,sp->rrep V; PUT2("%.1f fbar2 %.1f rdots\n", x, x-10) x -= 10; for (n=1; nlrep; n++) { x -= 6; PUT1("%.1f rdots\n", x) V3 "%s: Repeat %d.\n",F,n V; } } elsif (sp->u == B_DREP) { V6 "%s: Double repeat.\n",F V; PUT2("%.1f fbar1 %.1f rdots\n", x-1, x+9) PUT2("%.1f fbar2 %.1f rdots\n", x+1, x-9) } elsif (sp->u == B_FAT1) { PUT1("%.1f fbar1\n", x) } elsif (sp->u == B_FAT2) { PUT1("%.1f fbar2\n", x) } elsif (sp->u == B_FAT3) { PUT1("%.1f fbar3\n", x) } elsif (sp->u == B_INVIS) { ; } else { fprintf(stderr,">>> dont know how to draw bar type %d\n", sp->u); } PUT1("/x %.2f def", x) top = drawDecos (x,sp,&top2); /* add decorations */ PUT0("\n") } /* ----- drawBarnums ------- */ void drawBarnums (fp) FILE *fp; { char *F="drawBarnums"; int i,last,ok,got_note; last=0; got_note=0; for (i=0;i0)) { /* Bar nums now kept in "achord" field */ if (last != 2) set_font (fp, cfmt.barlabelfont, 0); PUT3 (" %.1f %.1f M (%s) cshow ", sym[i].x, BNUMHT, sym[i].ach) last=2; } elsif ((sym[i].type == BAR) && sym[i].ann) { /* Barnums may be done as annotation */ if (last != 2) set_font (fp, cfmt.barlabelfont, 0); PUT3 (" %.1f %.1f M (%s) cshow ", sym[i].x, BNUMHT, sym[i].ann->t) last=2; } if ((sym[i].type == BAR) && sym[i].t) { ok=0; if ((cfmt.barnums>0) && (sym[i].t%cfmt.barnums == 0)) ok=1; if ((cfmt.barnums == 0) && (!got_note)) ok=1; if ((cfmt.barnums!=0) && ((strlen(sym[i].ach)>0))) ok=0; V5 "%s: ok=%d.\n",F,ok V; if (ok) { if (last != 1) set_font (fp, cfmt.barnumfont, 0); /*| if ((mvoice>1) && (cfmt.barnums == 0)) |*/ if (cfmt.barnums == 0) PUT1 (" 0 38 M (%d) rshow ", sym[i].t) else PUT3 (" %.1f %.1f M (%d) cshow ", sym[i].x, BNUMHT, sym[i].t) last=1; } } } PUT0("\n"); } /* ----- update_endings: remember where to draw endings ------- */ void update_endings (float x,Sym s) { int i; if (num_ending>0) { i=num_ending-1; if (ending[i].num == 1) { mes1++; } else { mes2++; if (mes2 == mes1) ending[i].b=x; } } if (s.v) { if (num_ending>0) if (ending[num_ending-1].num == 1) ending[num_ending-1].b=x-3; ending[num_ending].a=x; ending[num_ending].b=-1; ending[num_ending].num=s.v; if (s.v == 1) mes1=0; else mes2=0; num_ending++; } } /* ----- set_ending: determine limits of ending box ------- */ void set_ending(i) int i; { char *F = "set_ending"; int num,j,j0,j1,mes,mesmax; char *vtxt; char *etxt; float top; num = sym[i].v; vtxt = sym[i].vtxt; V5 "%s: Called with i=%d num=%d vtxt=\"%s\"\n",F,i,num,vtxt V; mesmax=0; if (num == 2) mesmax=mes1; mes=0; j0=j1=-1; for (j=i+1;j0 || *sym[j].vtxt) { j0 = j; break; } if (mes == mesmax) { j0 = j; break; } } } top=-1; if (j0 == -1) j0=j1; if (j0>=0) top=sym[j0].x; if (*sym[i].vtxt) { ending[num_ending].num = num; strcpy(ending[num_ending].etxt,sym[i].vtxt); V5 "%s: num=%d v=%d vtxt=\"%s\" etxt=\"$x\" (from sym[%d].vtxt)\n" ,F,num,sym[i].v,sym[i].vtxt,ending[num_ending].etxt,i V; } else { ending[num_ending].num = num; sprintf(ending[num_ending].etxt,"%d\0",sym[i].v); V5 "%s: num=%d v=%d vtxt=\"%s\" etxt=\"$x\" (from sym[%d].v)\n" ,F,num,sym[i].v,sym[i].vtxt,ending[num_ending].etxt,i V; } ending[num_ending].a=sym[i].x; ending[num_ending].b=top; if (num == 1) ending[num_ending].b=top-3; ending[num_ending].type=E_CLOSED; if (sym[j0].type == BAR && sym[j0].u == B_SNGL) ending[num_ending].type=E_OPEN; num_ending++; if (num == 1) mes1=mes; if (num == 2) mes1=0; } /* ----- drawEnds ------- */ void drawEnds () { char *F="drawEnds"; int b, i; for (i=0;igr.n; if (n == 0) return; facx=0.3; fac=d/w-1; if (fac<0) fac=0; fac=1+(fac*facx)/(fac+facx); dx=0; for (m=0;mnpitch;m++) { /* room for accidentals */ dd=-s->shhd[m]; if (s->accs[m]) dd=-s->shhd[m]+s->shac[m]; if ((s->accs[m] == A_FT)||(s->accs[m] == A_NT)) dd=dd-2; if (dx=0;i--) { /* set note positions */ yg[i] = 3*(s->gr.p[i]-18) + s->yadd; if (i == n-1) { /* some subtle shifts.. */ if(yg[i]>=s->ymx) xx=xx+1; /* gnote above a bit closer */ if((yg[i]ymn-7)&&(n == 1)) xx=xx-2; /* below with flag further */ } if (iyg[i+1]+8) xx=xx+fac*1.8; } xg[i]=xx; xx=xx-fac*GSPACE; if (s->gr.a[i]) xx=xx-3.5; } if (n>1) { s1=sx=sy=sxx=sxy=0; /* linear fit through stems */ for (i=0;iBEAM_SLOPE) a=BEAM_SLOPE; if (a<-BEAM_SLOPE) a=-BEAM_SLOPE; b=(sy-a*sx)/s1; if (bagpipe) { a=0; b=35; } lmin=100; /* shift to get min stems */ for (i=0;i1) { px[i]=xg[i]+GSTEM_XOFF; py[i]=a*px[i]+b; lg=py[i]-yg[i]; PUT3("%.1f %.1f %.1f gnt ", xg[i],yg[i],lg) } else { lg=GSTEM; PUT3("%.1f %.1f %.1f gn1 ", xg[i],yg[i],lg) } acc=s->gr.a[i]; if (acc == A_SH) PUT2("%.1f %.1f gsh0 ",xg[i]-4.5,yg[i]) if (acc == A_HSH) PUT2("%.1f %.1f ghsh0 ",xg[i]-4.5,yg[i]) if (acc == A_FT) PUT2("%.1f %.1f gft0 ",xg[i]-4.5,yg[i]) if (acc == A_HFT) PUT2("%.1f %.1f ghft0 ",xg[i]-4.5,yg[i]) if (acc == A_NT) PUT2("%.1f %.1f gnt0 ",xg[i]-4.5,yg[i]) if (acc == A_DS) PUT2("%.1f %.1f gds0 ",xg[i]-4.5,yg[i]) if (acc == A_DF) PUT2("%.1f %.1f gdf0 ",xg[i]-4.5,yg[i]) y = (int)yg[i]; /* helper lines */ if (y<=-6) { if (y%6) PUT2("%.1f %d ghl ",xg[i], y+3) else PUT2("%.1f %d ghl ",xg[i], y) } if (y>=30) { if (y%6) PUT2("%.1f %d ghl ",xg[i], y-3) else PUT2("%.1f %d ghl ",xg[i], y) } } if (n>1) /* beam */ if (bagpipe) PUT4("%.1f %.1f %.1f %.1f gbm3 ", px[0],py[0],px[n-1],py[n-1]) else PUT4("%.1f %.1f %.1f %.1f gbm2 ", px[0],py[0],px[n-1],py[n-1]) if (slurgraces) { /* slur */ V3 "Slur grace notes.\n" V; bet1=0.2; bet2=0.8; yy=1000; for (i=n-1;i>=0;i--) if (yg[i]<=yy) {yy=yg[i]; ii=i;} x0=xg[ii]; y0=yg[ii]-5; if (ii>0) { x0=x0-4; y0=y0+1; } x3=x-1; y3=s->ymn-5; dy1=(x3-x0)*0.4; if (dy1>3) dy1=3; dy2=dy1; if (yg[ii]>s->ymn+7){ x0=xg[ii]-1; y0=yg[ii]-4.5; y3=s->ymn+1.5; x3=x-dx-5.5; dy2=(y0-y3)*0.2; dy1=(y0-y3)*0.8; bet1=0.0; } if (y3>y0+4) { y3=y0+4; x0=xg[ii]+2; y0=yg[ii]-4; } x1=bet1*x3+(1-bet1)*x0; y1=bet1*y3+(1-bet1)*y0-dy1; x2=bet2*x3+(1-bet2)*x0; y2=bet2*y3+(1-bet2)*y0-dy2; PUT4(" %.1f %.1f %.1f %.1f", x1,y1,x2,y2); PUT4(" %.1f %.1f %.1f %.1f gsl\n", x3,y3,x0,y0); } else { V3 "Detach grace notes.\n" V; } } /* ----- drawBasicNote: draw m-th head with accidentals and dots -- */ void drawBasicNote( float x, float w, float d, Sym *s, int m) { char *F="drawBasicNote"; int y,i,yy; float dotx,doty,xx,dx,avail,add,fac; y = 3 * (s->vpos[m] - 18); // + s->yadd; /* height on staff */ V5 "%s: y=%.2f from pits[%d]=%d vpos[%d]=%d pitadj=%d yadd=%d.\n", F,y,m,s->pits[m],m,s->vpos[m],s->pitadj,s->yadd V; xx = x + s->shhd[m]; /* draw head */ PUT2("%.1f %d", xx, y) if (s->head == H_OVAL) PUT0(" HD") if (s->head == H_EMPTY) PUT0(" Hd") if (s->head == H_FULL) PUT0(" hd") if (s->shhd[m]) { yy=0; if (y>=30) { yy=y; if (yy%6) yy=yy-3; } if (y<=-6) { yy=y; if (yy%6) yy=yy+3; } if (yy) PUT1(" %d hl", yy) } if (s->dots) { /* add dots */ if (y%6) { dotx=8; doty=0; } else { dotx=8; doty=3; } if (s->stem == -1) dotx=dotx+s->xmx-s->shhd[m]; else dotx=dotx+s->xmx-s->shhd[m]; if (s->dots && s->flags && (s->stem == 1) && !(y%6)) if ((s->word_st == 1) && (s->word_end == 1) && (s->npitch == 1)) dotx=dotx+DOTSHIFT; if (s->head == H_EMPTY) dotx=dotx+1; if (s->head == H_OVAL) dotx=dotx+2; for (i=0;idots;i++) { PUT2(" %.1f %.1f dt", dotx, doty) dotx=dotx+3.5; } } if (s->accs[m]) { /* add accidentals */ fac=1.0; avail=d-w-3; add=0.3*avail; fac=1+add/s->wl; if (fac<1) fac=1; if (fac>1.2) fac=1.2; dx=fac*s->shac[m]; if (s->accs[m] == A_SH) PUT1(" %.1f sh", dx) if (s->accs[m] == A_HSH) PUT1(" %.1f hsh", dx) if (s->accs[m] == A_NT) PUT1(" %.1f nt", dx) if (s->accs[m] == A_FT) PUT1(" %.1f ft", dx) if (s->accs[m] == A_HFT) PUT1(" %.1f hft", dx) if (s->accs[m] == A_DS) PUT1(" %.1f dsh", dx) if (s->accs[m] == A_DF) PUT1(" %.1f dft", dx) } } /* ----- drawDecos ----- */ float drawDecos (float x, Sym *s, float *tp) { char *F = "drawDecos"; int y,sig,k,deco,m; float yc,xc,y1,top,top1,dx,dy; V5 "%s: Sym has %d decorations.\n",F,s->dc.n V; top = -1000; for (k=s->dc.n-1; k>=0; k--) { /* decos close to head */ deco=s->dc.t[k]; if (deco == D_STACC) { /* dot */ sig=1; if (s->stem == 1) sig=-1; y = s->y + 6*sig; if (y=0) && (y<=24)) y+=3*sig; if (topymn; xc=5; for (m=0;mnpitch;m++) { dx=5-s->shhd[m]; if (s->head == H_OVAL) dx=dx+2.5; if (s->accs[m]) dx=4-s->shhd[m]+s->shac[m]; dy = 3 * (s->vpos[m]-18) + s->yadd - yc; if ((dy<10) && (dx>xc)) xc=dx; } yc=s->ymn; PUT2(" %.1f %.1f sld", yc, xc) } } top1=top; for (k=s->dc.n-1;k>=0;k--) { /* decos further away */ deco = s->dc.t[k]; V5 "%s: Deco %d is type %d.\n",F,k,deco V; if (deco == D_EMBAR) { /* bar */ yc=s->ymx+6; if (s->stem == 1) yc=s->ys+4; if (yc<28) yc=28; if (ycymx+9; if (s->stem == 1) yc=s->ys+5; if (yc<30) yc=30; if (ycy; if (s->stem == 1) { yc=s->y-5; if (yc>-2) yc=-2; PUT1(" %.2f cpd", yc) } else { yc=s->y+5; if (s->dots && (!(y%6))) yc=s->y+6; if (yc<26) yc=26; if (ycstem == 1) { y1=s->ys+4; } else { y1=s->ymx+6; } if (ycstem == 1) { y1=s->ys+4; } else { y1=s->ymx+6; } if (ycstem == 1) { y1=s->ys+4; } else { y1=s->ymx+6; } if (ycstem == 1) { y1=s->ys+5; } else { y1=s->ymx+7; } if (ycstem == 1) y1=s->ys+4; else y1=s->ymx+8; if (ycstem == 1) { c = 'u'; cc = 'd'; } slen = s->stem * (s->ys - s->y); for (m = 0; m < s->npitch; m++) { if (m>0) PUT0(" ") drawBasicNote(x,w,d,s,m); /* draw note heads */ V6 "%s: Note m=%d has pits[%d]=%d vpos[%d]=%d pitadj=%d stem=%d yadd=%d y=%6.3f\n", F,m,m,s->pits[m],m,s->vpos[m],s->pitadj,s->stem,s->yadd,s->y V; xx = 3 * (s->vpos[m] - 18) - s->y; // + s->yadd; V6 "xx=%.4f from vpos=%d y=%.3f\n",xx,s->vpos[m],s->y V; xx = xx * xx; V6 "xx=%.4f\n",xx V; if (xx<0.01) { /* add stem */ V5 "%s: stem=%d slen=%.1f c='%c'\n",F,s->stem,slen,c V; if (s->stem) PUT2(" %.1f s%c",slen,c) if (fl && (s->flags>0)) /* add flags */ PUT3(" %.1f f%d%c",slen,s->flags,c) } else { V5 "%s: No stem because xx=%.6f\n",F,xx V; } if ((m>0) && (s->vpos[m] == s->vpos[m-1])) { /* unions */ if (s->stem) PUT2(" %.2f s%c",slen0,cc) if (s->flags>0) PUT3(" %.1f f%d%c",slen0,s->flags,cc) } } top = drawDecos (x,s,&top2); /* add decorations */ y = s->ymn; /* lower helper lines */ if (y<=-6) { for (i = -6; i >= y; i -= 6) { PUT1(" %d hl", i) } if (s->head == H_OVAL) PUT0("1") } y = s->ymx; /* upper helper lines */ if (y>=30) { for (i = 30; i <= y; i += 6) { PUT1(" %d hl", i) } if (s->head == H_OVAL) PUT0("1") } switch (s->achp) { default: case 0: case P_ABOVE: *achy = s->achy ? s->achy : DflChYYAf; V5 "%s: achy=%6.3f [ABOVE]\n",F,*achy V; break; case P_BELOW: *achy = s->achy ? s->achy : -12.01; V5 "%s: achy=%6.3f [BELOW]\n",F,*achy V; break; } V5 "%s: achy=%6.3f\n",F,*achy V; if (strlen(s->ach)>0) { /* position accomp chord */ yc = *achy; if (ycys+4) yc=s->ys+4; for (k=0;kdc.n;k++) { if ((s->dc.t[k] == D_GRACE) && (ycann) { /* Is there an annotation? */ switch (s->ann->p) { default: case 0: case P_ABOVE: *anny = s->ann->y ? s->ann->y : DflChYYAf; break; case P_BELOW: *anny = s->ann->y ? s->ann->y : -12.01; break; } V5 "%s: anny=%6.3f\n",F,*anny V; V5 "%s: Annotation !%s! p=%d y=%6.3f\n",F,s->ann->t,s->ann->p,s->ann->y V; yc = *anny; V5 "%s: yc set to anny=%6.3f\n",F,yc V; if (s->ann->p == P_ABOVE) { if (yc < y+8) { yc = y+8; V5 "%s: yc changed to y+8=%6.3f\n",F,yc V; } if (yc < s->ys+4) { yc = s->ys+4; V5 "%s: yc changed to y+8=%6.3f\n",F,yc V; } for (k=0;kdc.n;k++) { if ((s->dc.t[k] == D_GRACE) && (yc0) iy=iy+6-ir; xx=iy*dir; return xx-x; } /* ----- rnd3: up/down shift needed to get k*3 ----- */ float rnd3(float x) { int ix,iy,ir; float xx; ix=x+600.999-1.5; ir=ix%3; iy=ix-600; if (ir>0) iy=iy+3-ir; xx=iy; return xx-x; } /* ----- rnd6: up/down shift needed to get k*6 ----- */ float rnd6(float x) { int ix,iy,ir; float xx; ix=x+600.999-3.0; ir=ix%6; iy=ix-600; if (ir>0) iy=iy+6-ir; xx=iy; return xx-x; } /* ----- b_pos ----- */ float b_pos (int stem, int flags, float b) { float bb,d1,d2,add; float top,bot; if (stem == 1) { top = b; bot = b - (flags-1) * BEAM_SHIFT - BEAM_DEPTH; if (bot > 26) return b; } else { bot = b; top = b + (flags-1) * BEAM_SHIFT + BEAM_DEPTH; if (top < -2) return b; } d1=rnd6(top-BEAM_OFFSET); d2=rnd6(bot+BEAM_OFFSET); add=d1; if (d1*d1>d2*d2) add=d2; bb=b+add; /* fprintf(stderr,"stem %d top %.1f, bot%.1f, choices %.1f %.1f => %.1f\n", stem, top,bot, d1,d2, add); */ /* fprintf(stderr,"b_pos(%d) b=%.1f to %.1f\n", stem,b,bb); */ return bb; } /* ----- calculate_beam ----- */ int calculate_beam (int i0, struct BEAM *bm) { char *F="calculate_beam"; int j,j1,j2,i,stem,notes,flags; float x,y,ys,a,b,max_stem_err,stem_err,min_stem,slen,yyg,yg,try; float s,sx,sy,sxx,sxy,syy,delta,hh,dev,dev2,a0; j1 = i0; /* find first and last note in beam */ j2 = -1; stem = sym[j1].stem; for (j=i0; j flags) flags = sym[j].flags; notes++; } } s=sx=sy=sxx=sxy=syy=0; /* linear fit through stem ends */ for (j=j1;j<=j2;j++) if (sym[j].type == NOTE) { x=sym[j].xs; y=sym[j].ymx+STEM*stem; s += 1; sx += x; sy += y; sxx += x*x; sxy += x*y; syy += y*y; } delta=s*sxx-sx*sx; /* beam fct: y=ax+b */ a=(s*sxy-sx*sy)/delta; b=(sy-a*sx)/s; /* the next few lines modify the slope of the beam */ if (notes>=3) { hh=syy-a*sxy-b*sy; /* flatten if notes not in line */ dev=0; if (hh>0) { dev2=hh/(notes-2); if (dev2>0.5) a=BEAM_FLATFAC*a; } } if (a>=0) a=BEAM_SLOPE*a/(BEAM_SLOPE+a); /* max steepness for beam */ else a=BEAM_SLOPE*a/(BEAM_SLOPE-a); /* to decide if to draw flat etc. use normalized slope a0 */ a0=a*(sym[j2].xs-sym[j1].xs)/(20*(notes-1)); if ((a0-BEAM_THRESH)) a=0; /* flat below threshhold */ b=(sy-a*sx)/s; /* recalculate b for new slope */ /* if (flags>1) b=b+2*stem;*/ /* leave a bit more room if several beams */ if (bagpipe) { b=-11; a=0; } max_stem_err=0; /* check stem lengths */ for (j=j1; j<=j2; j++) { if (sym[j].type == NOTE) { if (sym[j].npitch == 1) { min_stem = STEM_MIN; if (sym[j].flags == 2) min_stem = STEM_MIN2; if (sym[j].flags == 3) min_stem = STEM_MIN3; if (sym[j].flags == 4) min_stem = STEM_MIN4; } else { min_stem=STEM_CH_MIN; if (sym[j].flags == 2) min_stem = STEM_CH_MIN2; if (sym[j].flags == 3) min_stem = STEM_CH_MIN3; if (sym[j].flags == 4) min_stem = STEM_CH_MIN4; } min_stem = min_stem + BEAM_DEPTH + BEAM_SHIFT * (sym[j].flags - 1); ys = a * sym[j].xs + b; if (stem == 1) slen = ys - sym[j].ymx; else slen = sym[j].ymn - ys; stem_err = min_stem - slen; if (stem_err > max_stem_err) max_stem_err = stem_err; } } if (max_stem_err > 0) /* shift beam if stems too short */ b = b + stem * max_stem_err; V5 "%s: b=%d stem=%d flags=%d.\n",F,b,stem,flags V; for (j=j1+1;j<=j2;j++) if (sym[j].type == NOTE) { /* room for gracenotes */ for (i=0;i0) b=b+try; } else { try=(yg)-(yyg+BEAM_DEPTH+7); if (try<0) b=b+try; } } } if ((a<0.01) && (a>-0.01)) /* shift flat beams onto staff lines */ b = b_pos(stem,flags,b); V5 "%s: b=%d stem=%d flags=%d.\n",F,b,stem,flags V; for (j=j1;j<=j2;j++) if (sym[j].type == NOTE) { /* final stems */ sym[j].ys=a*sym[j].xs+b; } bm->i1=j1; /* save beam parameters in struct */ bm->i2=j2; bm->a=a; bm->b=b; bm->stem=stem; bm->t=stem*BEAM_DEPTH; return 1; } /* ----- rest_under_beam ----- */ float rest_under_beam (float x, int head, struct BEAM *bm) { float y,tspace,bspace; int j1,j2,j,nf,iy; tspace=9; bspace=11; if ((head == H_OVAL)||(head == H_EMPTY)) tspace=bspace=4; j1=bm->i1; j2=bm->i2; nf=0; for (j=j1;j<=j2;j++) if ((sym[j].type == NOTE)||(sym[j].flags>nf)) nf=sym[j].flags; if (bm->stem == 1) { y=bm->a*x+bm->b; y=y-BEAM_DEPTH-(nf-1)*BEAM_SHIFT; y=y-tspace; if (y>12) y=12; } else { y=bm->a*x+bm->b; y=y+BEAM_DEPTH+(nf-1)*BEAM_SHIFT; y=y+bspace; if (y<12) y=12; } if ((head == H_OVAL)||(head == H_EMPTY)) { iy=(y+3.0)/6.0; y=6*iy; } return y; } /* ----- drawBeamN: draw number on a beam ----- */ void drawBeamN (struct BEAM *bm, int num, float xn) { float yn; if (bm->stem == -1) { yn = bm->a * xn + bm->b - 12; } else { yn = bm->a * xn + bm->b + 4; } PUT3("%.1f %.1f (%d) bnum\n", xn, yn, num) } /* ----- drawBeam: draw a single beam ----- */ void drawBeam (float x1, float x2, float dy, struct BEAM *bm) { float y1,y2; y1=bm->a*x1+bm->b-bm->stem*dy; y2=bm->a*x2+bm->b-bm->stem*dy; PUT5("%.1f %.1f %.1f %.1f %.1f bm\n", x1,y1,x2,y2,bm->t) } /* ----- drawBeams: draw the beams for one word ----- */ void drawBeams (bm) struct BEAM *bm; { int j,j1,j2,j3,inbeam,k1,k2,num,p,r; float x1,x2,xn; j1=bm->i1; j2=bm->i2; /* make first beam over whole word */ x1=sym[j1].xs; x2=sym[j2].xs; num=sym[j1].u; for (j=j1;j<=j2;j++) { /* numbers for nplets on same beam */ if (sym[j].p_plet>0) { p=sym[j].p_plet; r=sym[j].r_plet; j3=j+r-1; if (j3<=j2) { xn=0.5*(sym[j].xs+sym[j3].xs); drawBeamN (bm,p,xn); sym[j].p_plet=0; } } } drawBeam (x1,x2,0.0,bm); /* second beams where two or more flags */ k1=0; inbeam=0; for (j=j1;j<=j2;j++) { if (sym[j].type!=NOTE) continue; if ((!inbeam) && (sym[j].flags>=2)) { k1=j; inbeam=1; } if (inbeam && ((sym[j].flags<2) || (j == j2))) { if ((sym[j].flags>=2) && (j == j2)) k2=j; x1=sym[k1].xs; x2=sym[k2].xs; inbeam=0; if (k1 == k2) { if (k1 == j1) drawBeam (x1+BEAM_STUB,x1,BEAM_SHIFT,bm); else drawBeam (x1-BEAM_STUB,x1,BEAM_SHIFT,bm); } else drawBeam (x1,x2,BEAM_SHIFT,bm); inbeam=0; } k2=j; } /* third beams where three or more flags */ k1=0; inbeam=0; for (j=j1;j<=j2;j++) { if (sym[j].type!=NOTE) continue; if ((!inbeam) && (sym[j].flags>=3)) { k1=j; inbeam=1; } if (inbeam && ((sym[j].flags<3) || (j == j2))) { if ((sym[j].flags>=3) && (j == j2)) k2=j; x1=sym[k1].xs; x2=sym[k2].xs; inbeam=0; if (k1 == k2) { if (k1 == j1) drawBeam (x1+BEAM_STUB,x1,2*BEAM_SHIFT,bm); else drawBeam (x1-BEAM_STUB,x1,2*BEAM_SHIFT,bm); } else drawBeam (x1,x2,2*BEAM_SHIFT,bm); inbeam=0; } k2=j; } /* fourth beams where four or more flags */ k1=0; inbeam=0; for (j=j1;j<=j2;j++) { if (sym[j].type!=NOTE) continue; if ((!inbeam) && (sym[j].flags>=4)) { k1=j; inbeam=1; } if (inbeam && ((sym[j].flags<4) || (j == j2))) { if ((sym[j].flags>=4) && (j == j2)) k2=j; x1=sym[k1].xs; x2=sym[k2].xs; inbeam=0; if (k1 == k2) { if (k1 == j1) drawBeam (x1+BEAM_STUB,x1,3*BEAM_SHIFT,bm); else drawBeam (x1-BEAM_STUB,x1,3*BEAM_SHIFT,bm); } else drawBeam (x1,x2,3*BEAM_SHIFT,bm); inbeam=0; } k2=j; } } /* ----- extreme: return min or max, depending on s ----- */ float extreme (float s, float a, float b) { if (s>0) { if (a>b) return a; return b; } else { if (a0) { if (s<0) s=0; if (s>s0) s=s0; } else { if (s>0) s=0; if (sdy) dy=yx-yy; } } ym=ym+dy; y1=ym+s*(x1-xm); y2=ym+s*(x2-xm); /* * shift up accomp chords, if needed */ for (j=j1;j<=j2;j++) { if ((sym[j].type == NOTE) || (sym[j].type == REST)) { xx = sym[j].x; yy = ym + (xx - xm) * s; if (sym[j].achy < yy+4) { sym[j].achy = yy+4; V5 "%s: sym[%d] achy=%6.3f ann->y=%6.3f [%s:%d]\n",F,j,sym[j].achy,sym[j].ann->y,FL V; } if (sym[j].ann) { if (sym[j].ann->y < yy+4) sym[j].ann->y = yy+4; V5 "%s: sym[%d] achy=%6.3f ann->y=%6.3f [%s:%d]\n",F,j,sym[j].achy,sym[j].ann->y,FL V; } else { V5 "%s: sym[%d] achy=%6.3f [%s:%d]\n",F,j,sym[j].achy,FL V; } } } // xx=xm-6; yy=ym+s*(xx-xm); PUT4("%.1f %.1f %.1f %.1f hbr ", x1,y1,xx,yy) // xx=xm+6; yy=ym+s*(xx-xm); PUT4("%.1f %.1f %.1f %.1f hbr ", x2,y2,xx,yy) // yy=0.5*(y1+y2); PUT3("%.1f %.1f (%d) bnum\n", xm, yy-4, p) } /* ----- drawNPletBkts ----- */ void drawNPletBkts () { int i,j,k,p,r,c; for (i=0;i0) { p=sym[i].p_plet; r=sym[i].r_plet; c=r; k=i; for (j=i;j4)) s=1; return s; } /* ----- outSlur: output slur -- --- */ void outSlur (float x1, float y1, float x2, float y2, float s, float height, float shift) { float alfa,beta,mx,my,xx1,yy1,xx2,yy2,dx,dy,dz,a,add; alfa=0.3; beta=0.45; /* for wide flat slurs, make shape more square */ dy=y2-y1; if (dy<0) dy=-dy; dx=x2-x1; if (dx<0) dx=-dx; a=dy/dx; if ((a<0.7) && dx>40) { add=0.2*(dx-40)/100; alfa=0.3+add; if (alfa>0.7) alfa=0.7; } /* alfa, beta, and height determine Bezier control points pp1,pp2 * * X == == alfa == =| == =alfa == == =X * / | \ * pp1 | pp2 * / height \ * beta | beta * / | \ * p1 m p2 * */ mx=0.5*(x1+x2); my=0.5*(y1+y2); xx1=mx+alfa*(x1-mx); yy1=my+alfa*(y1-my)+height; xx1=x1+beta*(xx1-x1); yy1=y1+beta*(yy1-y1); xx2=mx+alfa*(x2-mx); yy2=my+alfa*(y2-my)+height; xx2=x2+beta*(xx2-x2); yy2=y2+beta*(yy2-y2); dx=0.03*(x2-x1); if (dx>10.0) dx=10.0; dy=1.0; dz=0.20; if (x2-x1>100) dz=dz+0.001*(x2-x1); if (dz>0.6) dz=0.6; PUT4("%.1f %.1f %.1f %.1f ", xx2-dx, yy2+shift+s*dy, xx1+dx, yy1+shift+s*dy) PUT3("%.1f %.1f 0 %.1f ", x1,y1+shift+s*dz,s*dz) PUT4("%.1f %.1f %.1f %.1f ", xx1,yy1+shift,xx2,yy2+shift) PUT4("%.1f %.1f %.1f %.1f SL\n", x2,y2+shift, x1,y1+shift) /*PUT4("%.2f %.2f %.2f %.2f ", xx1,yy1+shift,xx2,yy2+shift) PUT4("%.2f %.2f %.2f %.2f sl\n", x2,y2+shift, x1,y1+shift)*/ return; } /* ----- drawSlur (not a pretty routine, this) ----- */ void drawSlur (int k1, int k2, int nn, int level) { float x01,x02,y01,y02; float x1,y1,x2,y2,yy,height,addx,addy; float s,shift,hmin,a; float x,y,z,h,dx,dy; int i; s=slur_direction (k1,k2); /* fix endpoints */ if (sym[k1].type == NOTE) { /* here if k1 points to note */ x01=sym[k1].x; yy=sym[k1].ymn; if (s>0) yy=sym[k1].ymx; y01=extreme(s,yy+s*6,sym[k1].ys+s*2); if (sym[k1].word_end) { yy=sym[k1].ymn; if (s>0) yy=sym[k1].ymx; y01=yy+s*6; if ((sym[k1].stem == 1)&&(s == 1)) x01=x01+4; } if ((s>0) && (y010) yy=sym[k2].ymx; y02=extreme(s,yy+s*6,sym[k2].ys+s*2); if (sym[k2].word_st) { yy=sym[k2].ymn; if (s>0) yy=sym[k2].ymx; y02=yy+s*6; if ((sym[k2].stem == -1)&&(s == -1)) x02=x02-3; } if ((s>0) && (y021) { if(s == 1) { if (y01<28) y01=28; } else { if (y01>-4) y01=-4; } } } if (sym[k2].type!=NOTE) { x02=sym[k2].x; y02=y01+1.2*s; if (nn>1) { if (s == 1) {if (y02<28) y02=28; } else {if (y02>-4) y02=-4; } } } /* shift endpoints */ addx=0.04*(x02-x01); if (addx>3.0) addx=3.0; addy=0.02*(x02-x01); if (addy>3.0) addy=3.0; x1 = x01+addx; x2 = x02-addx; y1=y01+s*addy; y2=y02+s*addy; a=(y2-y1)/(x2-x1); /* slur steepness */ if (a > SLUR_SLOPE) a= SLUR_SLOPE; if (a < -SLUR_SLOPE) a=-SLUR_SLOPE; if (a>0) { if (s == 1) y1=y2-a*(x2-x1); if (s == -1) y2=y1+a*(x2-x1); } else { if (s == -1) y1=y2-a*(x2-x1); if (s == 1) y2=y1+a*(x2-x1); } /* for big vertical jump, shift endpoints */ y=y2-y1; if (y>8) y=8; if (y<-8) y=-8; z=y; if(z<0) z=-z; dx=0.5*z; dy=0.3*z; if (y>0) { if (s == 1) { x2=x2-dx; y2=y2-dy; } if (s == -1) { x1=x1+dx; y1=y1+dy; } } else { if (s == 1) { x1=x1+dx; y1=y1-dy; } if (s == -1) { x2=x2-dx; y2=y2+dy; } } h=0; for (i=k1+1; i0) yy=sym[i].ymx; y = extreme (s, yy+6*s, sym[i].ys+2*s); z = (y2*(x-x1)+y1*(x2-x))/(x2-x1); h = extreme (s, h, y-z); } y1=y1+0.4*h; y2=y2+0.4*h; h=0.6*h; hmin=s*(0.03*(x2-x1)+8); if (nn>3) hmin=s*(0.12*(x2-x1)+12); height = extreme (s, hmin, 3.0*h); height = extreme (-s, height, s*50); y=y2-y1; if (y<0) y=-y; if ((s == 1) && (height< 0.8*y)) height=0.8*y; if ((s == -1) && (height>-0.8*y)) height=-0.8*y; shift=3*s*level; outSlur (x1,y1,x2,y2,s,height,shift); return; } /* ----- prev_scut, next_scut: find place to terminate/start slur --- */ int next_scut (int i) { int j,cut,ok; cut=nsym-1; for (j=i+1;j=0;j--) { ok=0; if (sym[j].type == BAR) { if (sym[j].u == B_LREP) ok=1; if (sym[j].u == B_DREP) ok=1; if (sym[j].u == B_FAT1) ok=1; if (sym[j].u == B_FAT2) ok=1; if (sym[j].u == B_FAT3) ok=1; if (sym[j].v == 2) ok=1; } if(ok) { cut=j; break; } } if (cut == -1) { /* return sym before first note */ cut=0; for (j=0;j ptop) ptop = p1; } for (i=0;i3.0) addx=3.0; addy=0.02*(x2-x1); if (addy>3.0) addy=3.0; x1=x1+3+addx; x2=x2-3-addx; if ((s == 1) && (sym[k1].stem == 1)) x1=x1+1.5; if ((s == -1) && (sym[k2].stem == -1)) x2=x2-1.5; y=3*(p1-18)+sym[k1].yadd; y1=y2=y+s*(4+addy); y=3*(p2-18)+sym[k2].yadd; y2=y+s*(4+addy); if ((s == 1) && !(y%6) && (sym[k1].dots>0)) { y2=y1=y+s*(5.5+addy); x1=x1-2; x2=x2+2; } height=s*(0.04*(x2-x1)+5); shift=0; outSlur (x1,y1,x2,y2,s,height,shift); } } /* ----- drawSlurs: draw slurs/ties between neighboring notes/chords */ void drawSlurs (k1,k2,job) int k1,k2,job; { char *F="drawSlurs"; int i,m1,m2; int mhead1[MAXHD],mhead2[MAXHD],nslur,nh1,nh2; if (nbuf+100>tunebuffsz) { V1 "%s: PS output exceeds reserved space staffbufsz=%d per staff -- increase staffbufsz\n",F,staffbufsz V; V1 "%s: nbuf=%d staffbufsz=%d tunebuffsz=%d.\n",F,nbuf,staffbufsz,tunebuffsz V; } nslur=0; if (job == 2) { /* half slurs from last note in line */ nh1=sym[k1].npitch; for (i=1;i<=nh1;i++) { for (m1=0;m1tunebuffsz) { V1 "%s: PS output exceeds reserved space per staff -- increase staffbufsz\n",F,staffbufsz V; V1 "%s: nbuf=%d staffbufsz=%d tunebuffsz=%d.\n",F,nbuf,staffbufsz,tunebuffsz V; } nn=0; for (i=k1;i<=k2;i++) if ((sym[i].type == NOTE)||(sym[i].type == REST)) nn++; drawSlur (k1,k2,nn,level); } /* ----- drawAllSlurs: draw all slurs/ties between neighboring notes */ void drawAllSlurs () { int i,i1,i2; i1=-1; for (i=0;i=0) { cut=next_scut(i); if (cut=0 && k2>=0) { if (symv[v][k1].u == B_RREP && symv[v][k2].u == B_LREP) { V2 "%s: RREP=%d + LREP=%d found.\n",F,symv[v][k1].rrep,symv[v][k1].lrep V; if ((symv[v][k1].rrep+symv[v][k1].lrep) < 1 && symv[v][k2].u < 2) { V6 "%s: RREP+LREP reduced to DREP.\n",F V; symv[v][k2].u = B_DREP; symv[v][k1].u = B_INVIS; } dx = -7.0; } } } xp[i].x += dx; } j=i; i=xp[i].next; if (i == ip2) break; } } /* ----- check_bars2 ---------- */ void check_bars2 (ip1,ip2) int ip1,ip2; { char *F = "check_bars2"; int i,ip,v; /* check whether to split up last bar over two lines */ ip=xp[ip2].prec; for (v=0;v=0) { if (symv[v][i].type == BAR) { if (symv[v][i].u == B_LREP) { symv[v][i].u=B_SNGL; voice[v].insert_btype=B_LREP; voice[v].insert_num=0; } elsif (symv[v][i].u == B_DREP) { symv[v][i].u=B_RREP; voice[v].insert_btype=B_LREP; voice[v].insert_num=0; } elsif ((symv[v][i].u == B_RREP) && (symv[v][i].v!=0)) { voice[v].insert_btype=B_INVIS; voice[v].insert_num=symv[v][i].v; symv[v][i].v=0; } elsif ((symv[v][i].u == B_SNGL) && (symv[v][i].v!=0)) { voice[v].insert_btype=B_INVIS; voice[v].insert_num=symv[v][i].v; symv[v][i].v=0; } /* if number or label on last bar, move to next line */ if (symv[v][i].t || (strlen(symv[v][i].ach)>0) || (symv[v][i].ann)) { if (symv[v][i+1].type == BAR) { if (symv[v][i+1].t == 0) { symv[v][i+1].t = symv[v][i].t; } if (strlen(symv[v][i+1].ach) == 0) { strcpy(symv[v][i+1].ach,symv[v][i].ach); } if (symv[v][i].ann && symv[v][i].ann->t && symv[v][i].ann->t[0]) { V1 "%s: Copy annotation from symv[%d][%d] to symv[%d][%d].\n",F,v,i,v,i+1 V; if (!symv[v][i+1].ann) { V6 "%s: Init annotation for voice %c sym %d.\n",F,v,i+1 V; TextInit(&symv[v][i+1].ann,64); } TextAppend(symv[v][i+1].ann,symv[v][i].ann->t); } } else { if (!voice[v].insert_btype) voice[v].insert_btype=B_INVIS; voice[v].insert_space=symv[v][i].wr; voice[v].insert_bnum=symv[v][i].t; strcpy(voice[v].insert_text,symv[v][i].ach); strcpy(symv[v][i].ach,""); if (symv[v][i].ann) { strcpy(voice[v].insert_text,symv[v][i].ann->t); V6 "%s: Init annotation for voice %d sym %d.\n",F,v,i V; TextInit(&symv[v][i].ann,64); symv[v][i].t = 0; } } } } } } } /* ----- drawVocals ----- */ void drawVocals (FILE *fp, int nwl, float botnote, float bspace, float *botpos) { int i,hyflag,l,j; float x,x0,yword,lastx,spc,vfsize,w,swfac,lskip; char word[81],t[81]; if (nwl<=0) return; vfsize=cfmt.vocalfont.size; lskip=1.1*vfsize; set_font (fp, cfmt.vocalfont, 0); yword=-cfmt.vocalspace; swfac=1.05; if (strstr(cfmt.vocalfont.name,"Helvetica")) swfac=1.10; if (botnote-cfmt.vocalfont.size1) && (word[l-1] == '^')) { word[l-1]='\0'; hyflag=1; } if ((l == 1) && (word[0] == '_')) { if (lastx<0) lastx=sym[i-1].x+sym[i-1].wr; PUT3("%.1f %.1f %.1f wln ", lastx+3, sym[i].x+1, yword) } elsif ((l == 1) && (word[0] == '^')) { PUT2("%.1f %.1f whf ", x0, yword) lastx=x0+vfsize*swfac*w; } else { tex_str (word,t,&w); if (isdigit(word[0])) x0=x0-3*vfsize*swfac*cwid('1'); else x0=x0-VOCPRE*vfsize*swfac*w; if (strcmp(t," ")) PUT3("(%s) %.1f %.1f wd ", t, x0, yword) lastx=x0+vfsize*swfac*w; } } } if (hyflag) PUT2("%.1f %.1f whf ",lastx+5,yword) yword=yword-lskip; } *botpos=yword + lskip - bspace; } /* ----- drawSyms: draw symbols at proper positions on staff ----- */ void drawSyms ( FILE *fp, float bspace, float *bpos, int is_top) { char *F = "drawSyms"; int i, inbeam, j, nwl; float x, y, top, xl, d, w, achy, anny, botnote, botpos, spc, swfac; struct BEAM bm; // Ksig *ks=0; char t[81]; V3 "%s: Called with vb=%d.\n",F,vb V; inbeam = 0; // do_words = 0; botnote = 0; nwl = 0; for (i=0; i nwl) nwl = j+1; } } if (nbuf+100>tunebuffsz) { V1 "%s: PS output exceeds reserved space per tune -- increase tunebuffsz=%d.\n",F,tunebuffsz V; V1 "%s: nbuf=%d staffbufsz=%d tunebuffsz=%d.\n",F,nbuf,staffbufsz,tunebuffsz V; } x = sym[i].x; switch (sym[i].type) { case NOTE: V6 "%s: NOTE x=%.2f y=%.2f w=[%.2f,%.2f] p=[%.2f,%.2f] x=[%.2f,%.2f]\n", F,sym[i].x,sym[i].y,sym[i].wl,sym[i].wr,sym[i].pl,sym[i].pr,sym[i].xl,sym[i].xr V; xl=0; w=sym[i].wl; if (i>0) { xl = sym[i-1].x; w = w + sym[i-1].wr; } d = x - xl; V6 "%s: x=%.2f xl=%.2f w=%.2f d=%.2f\n",F,x,xl,w,d V; if (sym[i].word_st && !sym[i].word_end) { if (calculate_beam (i,&bm)) inbeam=1; } if (inbeam) { top = drawNote(x,w,d,&sym[i],0,&achy,&anny); V5 "%s: drawNote returned top=%6.3f achy=%6.3f anny=%6.3f\n",F,top,achy,anny V; if (i == bm.i2) { inbeam=0; drawBeams (&bm); } } else { top = drawNote(x,w,d,&sym[i],1,&achy,&anny); V5 "%s: drawNote returned top=%6.3f achy=%6.3f anny=%6.3f\n",F,top,achy,anny V; } sym[i].achy = achy; if (sym[i].ann) { sym[i].ann->y = anny; } sym[i].dc.top = top; V5 "%s: NOTE achy=%6.3f anny=%6.3f top=%6.3f\n",F,achy,anny,top V; if (sym[i].ymn-50) { xl = sym[i-1].x; w = w + sym[i-1].wr; } d = x - xl; // Copied from NOTE case by jc. y = sym[i].y; V6 "%s: REST at y=%.2f\n",F,y V; if (inbeam) y=rest_under_beam (sym[i].x,sym[i].head,&bm); drawRest(x,w,d,y,sym[i],&achy,&anny); sym[i].achy = achy; if (sym[i].ann) sym[i].ann->y = anny; V5 "%s: REST achy=%6.3f anny=%6.3f top=%6.3f\n",F,achy,anny,top V; break; case BAR: V6 "%s: BAR\n",F V; xl=0; w=sym[i].wl; if (i>0) { xl = sym[i-1].x; w = w + sym[i-1].wr; } d = x - xl; V5 "%s: BAR x=%.2f xl=%.2f d=%.2f w=%.2f\n",F,x,xl,d,w V; if (sym[i].v) set_ending(i); drawBar(x,w,d,&sym[i]); break; case CLEF: V6 "%s: CLEF sym %d u=%d v=%d w=%d.\n",F,i,sym[i].u,sym[i].v,sym[i].w V; switch (sym[i].u) { case NOCLEF: // No clef. V6 "%s: NOCLEF\n",F V; PUT1("%.1f nclef\n", x) break; case TREBLE: V6 "%s: TREBLE clef\n",F V; if (sym[i].v) PUT1("%.1f stclef\n", x) else PUT1("%.1f tclef\n", x) break; case TENOR: V6 "%s: TENOR clef\n",F V; case TREBLEd8: V6 "%s: TREBLEd8 clef\n",F V; if (sym[i].v) PUT1("%.1f std8clef\n", x) else PUT1("%.1f td8clef\n", x) break; case TREBLEu8: V6 "%s: TREBLEu8 clef\n",F V; if (sym[i].v) PUT1("%.1f stu8clef\n", x) else PUT1("%.1f tu8clef\n", x) break; case BASS: V6 "%s: BASS clef\n",F V; if (sym[i].v) PUT1("%.1f sbclef\n", x) else PUT1("%.1f bclef\n", x) break; case BASSd8: V6 "%s: BASSd8 clef\n",F V; if (sym[i].v) PUT1("%.1f sbd8clef\n", x) else PUT1("%.1f bd8clef\n", x) break; case BASSu8: V6 "%s: BASSu8 clef\n",F V; if (sym[i].v) PUT1("%.1f sbu8clef\n", x) else PUT1("%.1f bu8clef\n", x) break; case ALTO: V6 "%s: ALTO clef\n",F V; if (sym[i].v) PUT1("%.1f scclef\n", x) else PUT1("%.1f cclef\n", x) break; case ALTOd8: V6 "%s: ALTOd8 clef\n",F V; if (sym[i].v) PUT1("%.1f scd8clef\n", x) else PUT1("%.1f cd8clef\n", x) break; case ALTOu8: V6 "%s: ALTOu8 clef\n",F V; if (sym[i].v) PUT1("%.1f scu8clef\n", x) else PUT1("%.1f cu8clef\n", x) break; default: V3 "%s: unknown clef type=%d u=%d v=%d.\n",F,sym[i].type,sym[i].u,sym[i].v V; if (sym[i].v) PUT1("%.1f stclef\n", x) else PUT1("%.1f tclef\n", x) } voice[ivc].key->data.clef=sym[i].u; break; case TIMESIG: V6 "%s: TIMESIG sym[%d] u=%d v=%d w=%d x=%6.3f.\n",F,i,sym[i].u,sym[i].v,sym[i].w,x V; draw_timesig(x,sym[i]); break; case KEYSIG: V6 "%s: KEYSIG voice[%d].key is %08lX %s\n",F,ivc,voice[ivc].key,dmpKsig(voice[ivc].key) V; V6 "%s: KEYSIG sym[%d].ksig is %08lX %s\n",F,i,sym[i].ksig,dmpKsig(sym[i].ksig) V; voice[ivc].key->data.sf = draw_ksig(i,x-3.0,sym[i]); V6 "%s: KEYSIG draw_ksig returned sf=%d.\n",F,voice[ivc].key->data.sf V; V6 "%s: KEYSIG voice[%d].key is %08lX %s\n",F,ivc,voice[ivc].key,dmpKsig(voice[ivc].key) V; V6 "%s: KEYSIG sym[%d].ksig is %08lX %s\n",F,i,sym[i].ksig,dmpKsig(sym[i].ksig) V; if (sym[i].ksig) asgnKsig(voice[ivc].key,sym[i].ksig); break; case INVISIBLE: V6 "%s: KEYSIG\n",F V; break; default: fprintf(stderr,">>> cannot draw symbol type %d\n", sym[i].type); } } drawNPletBkts (); if (ivc == ivc0) drawBarnums(fp); /* draw accomp chords */ if (voice[ivc].do_ach) { set_font(fp,cfmt.achordfont,0); swfac=1.0; if (strstr(cfmt.achordfont.name,"Times-Roman")) swfac=1.00; if (strstr(cfmt.achordfont.name,"Times-Courier")) swfac=1.05; if (strstr(cfmt.achordfont.name,"Helvetica")) swfac=1.10; if (strstr(cfmt.achordfont.name,"Helvetica-Bold")) swfac=1.15; for (i=0;i4.0) spc = 4.0; V5 "%s: sym[%d] x=%6.3f achy=%6.3f spc=%6.3f ach !%s!\n",F,i,sym[i].x,sym[i].achy,spc,sym[i].ach V; PUT3("%.1f %.1f (%s) ach ", sym[i].x-spc, sym[i].achy, t) } V5 "%s: sym[%d].ann=%X\n",F,i,sym[i].ann V; if (sym[i].ann) { V5 "%s: sym[%d].ann=%X l=%d m=%d.\n",F,i,sym[i].ann,sym[i].ann->l,sym[i].ann->m V; if (*sym[i].ann->t) { V5 "%s: sym[%d].ann=!%s!\n",F,i,sym[i].ann->t V; tex_str (sym[i].ann->t,t,&w); w = cfmt.annotfont.size*w; spc = w*GCHPRE; if (spc > 4.0) spc = 4.0; V5 "%s: sym[%d] x=%6.3f anny=%6.3f spc=%6.3f ann !%s!\n", F,i,sym[i].x,sym[i].ann->y,spc,sym[i].ann->t V; PUT3("%.1f %.1f (%s) ann ", sym[i].x-spc, sym[i].ann->y, t) } } } } } drawAllSlurs (); drawAllPhrasings (); /*| if (is_top) drawEnds (); |*/ if (ivc == ivc0) drawEnds (); num_ending=0; botpos=-bspace; if (botnote0) drawVocals (fp,nwl,botnote,bspace,&botpos); *bpos=botpos; } /* ----- drawSysBars: draw bars extending over staves----- */ void drawSysBars (FILE *fp, int ip1, int ip2, float wid0, float h1, float dh) { int i,v,ok,u,uu,p; float x; PUT2 ("gsave 0 %.2f T 1.0 %.4f scale ",h1,dh/24.0) i=ip1; for (;;) { if (xp[i].type == BAR) { p=xp[i].p[ivc0]; u=symv[ivc0][p].u; if (u == B_LREP) u=B_FAT1; if (u == B_RREP) u=B_FAT2; ok=1; for (v=0;v= jv-iv+1) { for (kv=iv;kv=0 && i=4) { fprintf(stderr,"Selection <%s> selected voices:",vcselstr); for (i=0;iwid) wid=w; if (job!=0) { xcc=xc; if (xcc+0.5*w>dx0) xcc=dx0-0.5*w; dy = 8.0 + 0.5*cfmt.voicefont.size*(n-1-2*i) + h; PUT3 (" %.2f %.2f M (%s) cshow\n",xcc,dy,t) } } return wid; } /* ----- mstave_deco: draw decorations over multiple staves ----- */ void mstave_deco (FILE *fp, int ip1, int ip2, float wid0, float hsys, float htab[]) { int iv,jv,nv; float hbot,htop,ht,x0,y0,wid,wc,wcb,w,wmin; float wmin1=15.0, wmin2=10.0; /* space to staff */ wmin=wmin2; if (do_indent) wmin=wmin1; /* draw bar lines */ if (mvoice>1) { for (iv=0;ivhtop)) htop=htab[jv]; } if ((hbot1)) drawSysBars (fp,ip1,ip2,wid0,hsys-htop,htop-hbot+24.0); } PUT1 ("gsave 1.0 %.4f scale 0.0 bar grestore\n", (hsys+24.0)/24.0) } /* next part draws voice names (except on braces) */ set_font (fp, cfmt.voicefont, 0); nv=0; for (iv=0;iv1) w=voice_label (fp, voice[iv].sname, 0.0,0.0,0.0, 0); if (w>wid) wid=w; } } wc=wcb=0.5*wid+wmin; if (wcb<18.0) wcb=18.0; /* label on brace needs a bit more room */ for (iv=0;iv1) voice_label (fp,voice[iv].sname,y0,-wc,-wmin,1); } } /* braces and brackets */ for (iv=0;ivhtop)) htop=htab[jv]; } if (hbot2) ht=ht-8.0; if ((nv>1)||(voice[iv].brace == 1)) PUT3 (" %.4f %.1f %.1f brace\n", ht/120.0, x0, y0) if (do_indent) voice_label (fp, voice[iv].name, y0-12.0,-wcb,-wmin,1); elsif (nv>1) voice_label (fp, voice[iv].sname,y0-12.0,-wcb,-wmin,1); } hbot=10000; htop=-hbot; nv=0; for (jv=iv;jvhtop)) htop=htab[jv]; } if ((hbot1)||(voice[iv].bracket == 1))) PUT2 ("\n %.1f -3 %.1f bracket\n", htop-hbot+24.0+6.0, hsys-htop-3.0) } } /* ----- outMusic: output for parsed symbol list ----- */ void outMusic (FILE *fp) { char *F = "outMusic"; int ip1,ip2,mv,is_top,nsel,b,bnum; float realwidth,staffwidth,wid0,widv,lscale,lwidth,bpos; float spa1,spa2,hsys,htab[40],extra,indent,spax,x; V6 "%s: Called for nvoice %d.\n",F,nvoice V; V6 "%s: default_key is %s\n",F,dmpKsig(&default_key) V; /* save current meter and key, to continue after P: or T: field */ for (ivc=0; ivc1) print_vsyms(); alfa_last = 0.1; beta_last = 0.0; lwidth = cfmt.staffwidth; lscale = cfmt.scale; check_margin(cfmt.leftmargin); /* dump buffer if not enough space for a staff line */ check_buffer(fp, staffbufsz); V4 "%s: initialize meter and key for voices\n",F V; for (ivc=0; ivc0) { mvoice++; if (ivc0<0) ivc0=ivc; voice[ivc].draw=1; } } if (mvoice == 0) { init_parse_params(); return; } for (ivc=0; ivcksig,dmpKsig(symv[ivc]->ksig) V; setSymWidths (0,voice[ivc].nsym,symv[ivc],ivc); if (ivc == ivc0) bnum = b; } } barinit = bnum; if (mvoice == 1) set_style_pars (cfmt.strict1); else set_style_pars (cfmt.strict2); set_poslist (); set_xpwid (); set_spaces (); if (make_audio) output_audio (); /* loop over pieces to output */ ip1 = xp[XP_START].next; for (;;) { mline++; ip1 = contract_ksigs(ip1); V6 "%s: contract_ksigs returned %d.\n",F,ip1 V; wid0 = 0; for (ivc=0; ivcwid0) wid0=widv; } indent = (do_indent == 1) ? cfmt.indent : 0.0; ip2 = select_piece (ip1); ip2 = check_overflow (ip1,ip2,lwidth/lscale-wid0-indent); V5 "%s: output posits %d to %d\n",F,ip1,ip2-1 V; realwidth = set_glue (ip1,ip2,lwidth/lscale-wid0-indent); check_bars1 (ip1,ip2); check_bars2 (ip1,ip2); spa1 = spa2 = cfmt.staffsep; if (mvoice>1) { spa1 = cfmt.systemsep; spa2 = cfmt.sysstaffsep; } hsys = 0; mv = 0; for (ivc=0; ivc1000.0) spax = voice[ivc].sep-2000.0; is_top = is_topvc(ivc); drawSyms (fp,0.5*spa2+spax-spa2,&bpos,is_top); if (mv == mvoice) mstave_deco (fp,ip1,ip2,wid0,hsys,htab); PUT0("grestore\n") x = -lscale * bpos; V5 "%s: Bskip(%.2f) lscale=%.2f bpos=%.2f [%s:%d]\n",F,x,lscale,bpos,FL V; Bskip(x); hsys=hsys+0.5*spa2+24.0-bpos; } } extra=-bpos-0.5*spa2; if (mvoice>1) { x = lscale*(spa1+bpos-0.5*spa1+extra); V5 "%s: Bskip(%.2f) spa1=%.2f bpos=%.2f extra=%.2f [%s:%d]\n",F,x,spa1,bpos,extra,FL V; Bskip(x); } buffer_eob (fp); do_meter=do_indent=0; ip1=ip2; if (ip1 == XP_END) break; } /* set things to continue parsing */ for (ivc=0;ivcv. Note * the use of the strings fields: * char *v; -- Value * int l; -- Length in use * int m; -- Bytes malloc'd (zero if not malloc'd) * char *p; -- Pointer into string * The return value is sp. A zero return value means that malloc() failed. */ Str *setStr(sp,val,len) Str *sp; char*val; int len; { char*F="setStr"; int siz = len+1; // length plus null terminator V3 "%s: Str:%X=[v=%X,l=%d,m=%d,p=%X] val='%s' len=%d.\n",F,sp,sp->v,sp->l,sp->m,sp->p,val,len V; unless (len>=0) { len = strlen(val); V3 "%s: Str:%X val='%s' len=%d.\n",F,sp,val,len V; } if (!sp->v || siz > sp->m) { V3 "%s: Gotta (re)alloc the string.\n",F V; if (sp->m && sp->v) { // Was the Str malloc'd? V3 "%s: Free old Str %X val at %X\n",F,sp,sp->v V; free(sp->v); // Free old value } V3 "%s: Alloc new Str %X val, %d bytes.\n",F,sp,siz V; unless (sp->v = (char*)malloc(siz)) { V1 "%s: ### OUT OF MEMORY (Can't get %d for Str) ###\n",F,siz V; return 0; } V3 "%s: Zero Str %X val at %X, %d bytes.\n",F,sp,sp->v,siz V; bzero(sp->v,siz); sp->m = siz; sp->l = 0; sp->p = 0; sp->q = 0; } V3 "%s: Copy val '%s' to sp->v=%X %d bytes.\n",F,val,sp->v,len V; bcopy(val,sp->v,len); sp->v[len] = 0; sp->l = len; V3 "%s: Str %X val at %X is '%s'\n",F,sp,sp->v,sp->v V; return sp; } Vdef *vdefs = 0; // List of voice definitions Vdef *vdefz = 0; // Last voice definition /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * The original code here accepted voice definitions only after the K header, * * inside the tune. The switch_voice does seem to need to use the key. So to * * make voice definitions work inside the header, what we do is accumulate * * the definitions in a list and not parse them yet. When we encounter the K * * header, we will parse the voice definitions. We are essentially moving the * * V lines to just after the K line. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ Vdef* voiceDef(lvoiceid,line) char *lvoiceid; Str *line; { char *F="voiceDef"; Vdef *vp=0; V3 "%s: Vdef %s \"%s\"\n",F,lvoiceid,line->v V; unless (vp = (Vdef*)malloc(sizeof(Vdef))) { V1 "%s: ### OUT OF MEMORY (Can't get %d for Vdef %s) ###\n",F,sizeof(Vdef),lvoiceid V; return 0; } bzero(vp,sizeof(Vdef)); unless (setStr(&vp->vid,lvoiceid,-1)) { V1 "%s: ### OUT OF MEMORY (Can't get %d for Vdef %s vid) ###\n",F,line->l+1,lvoiceid V; free(vp); return 0; } unless (setStr(&vp->src,line->v,line->l)) { V1 "%s: ### OUT OF MEMORY (Can't get %d for Vdef %s string) ###\n",F,line->l+1,lvoiceid V; free(vp->vid.v); free(vp); return 0; } if (vdefz) { vdefz->next = vp; vdefz = vp; } else { vdefs = vdefz = vp; } if (vb > 4) { for (vp = vdefs; vp; vp = vp->next) { V5 "%s: Saved voice \"%s\"\n",F,vp->src.v V; } } return vp; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void doLine(fp,type,xref_str,npat,pat,sel_all,search_field) FILE *fp; // File needed if line continued int type; // Line type code char xref_str[]; int npat; char pat[][STRL1]; int sel_all; int search_field; { char *F = "doLine"; char fnm[81],finf[MAXINF]; Vdef *vp; FILE *feps; if ((vb>15) || ((verbose>10)&&within_block)) { V5 "%s: type %d\n",F,type V; print_linetype(type); } switch (type) { case XREF: /* start of new block */ if (!epsf) write_buffer (fp); /* flush stuff left from %% lines */ if (within_block) fprintf(stderr,"\n+++ Last tune not closed properly\n"); get_default_info (); within_block = 1; within_tune = 0; do_this_tune = 0; numtitle=0; ntext=0; init_pdims(); cfmt=dfmt; break; case TITLE: if (!within_block) break; if (within_tune) { /* title within tune */ if (do_this_tune ) { outMusic (fp); write_inside_title (fp); do_meter=do_indent=1; barinit=1; } } else { check_selected(fp,xref_str,npat,pat,sel_all,search_field); } break; case TEMPO: if (!within_block) break; if (within_tune) { /* tempo within tune */ if (do_this_tune ) { outMusic (fp); write_inside_tempo(fp); } } else { check_selected(fp,xref_str,npat,pat,sel_all,search_field); } break; case KEY: V4 "%s: KEY\n",F V; if (!within_block) { V4 "%s: Key not within block.\n",F V; break; } if (within_tune) { V4 "%s: Key within tune.\n",F V; if (do_this_tune) { V4 "%s: Doing this tune.\n",F V; handle_inside_field(type); } } else { V4 "%s: Key within headers; start of tune.\n",F V; check_selected(fp,xref_str,npat,pat,sel_all,search_field); if (do_this_tune) { V4 "%s: Doing this tune.\n",F V; tunenum++; V4 "%s: Start tune %d (%s) ===