mirror of
https://github.com/sshlien/abcmidi.git
synced 2025-12-06 06:55:06 +00:00
abcMIDI-2020.07.06.zip
This commit is contained in:
495
position.c
Normal file
495
position.c
Normal file
@@ -0,0 +1,495 @@
|
||||
/*
|
||||
* yaps - program to convert abc files to PostScript.
|
||||
* Copyright (C) 1999 James Allwright
|
||||
* e-mail: J.R.Allwright@westminster.ac.uk
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*
|
||||
*/
|
||||
|
||||
/* position.c */
|
||||
/* part of YAPS - abc to PostScript converter */
|
||||
/* This file contains routines to calculate symbol positions within */
|
||||
/* a line of music. */
|
||||
|
||||
/* for Microsoft Visual C++ 6.0 and higher */
|
||||
#ifdef _MSC_VER
|
||||
#define ANSILIBS
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef ANSILIBS
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#include "abc.h"
|
||||
#include "structs.h"
|
||||
#include "sizes.h"
|
||||
|
||||
extern struct tune thetune;
|
||||
extern double scaledwidth;
|
||||
|
||||
static void addfract(f, n, m)
|
||||
struct fract* f;
|
||||
int n, m;
|
||||
/* add n/m to fraction pointed to by f */
|
||||
/* like addunits(), but does not use unitlength */
|
||||
{
|
||||
f->num = n*f->denom + m*f->num;
|
||||
f->denom = m*f->denom;
|
||||
reducef(f);
|
||||
}
|
||||
|
||||
static void mulfract(f, n, m)
|
||||
struct fract* f;
|
||||
int n, m;
|
||||
/* multiply n/m to fraction pointed to by f */
|
||||
/* like addunits(), but does not use unitlength */
|
||||
{
|
||||
f->num = n*f->num;
|
||||
f->denom = m*f->denom;
|
||||
reducef(f);
|
||||
}
|
||||
|
||||
static void advance(struct voice* v, int phase, int* items, double* itemspace, double x)
|
||||
/* move on one symbol in the specified voice */
|
||||
{
|
||||
struct feature* p;
|
||||
struct rest* arest;
|
||||
struct note* anote;
|
||||
struct fract tuplefactor, notelen;
|
||||
int done;
|
||||
int stepon;
|
||||
int zerotime, newline;
|
||||
|
||||
switch(phase) {
|
||||
case 1:
|
||||
zerotime = 1;
|
||||
newline=0;
|
||||
break;
|
||||
case 2:
|
||||
zerotime = 0;
|
||||
newline=0;
|
||||
break;
|
||||
case 3:
|
||||
zerotime = 0;
|
||||
newline=1;
|
||||
break;
|
||||
default:
|
||||
printf("Internal error: phase = %d\n", phase);
|
||||
exit(1);
|
||||
break;
|
||||
};
|
||||
|
||||
*itemspace = 0.0;
|
||||
*items = 0;
|
||||
p = v->place;
|
||||
if (p == NULL) {
|
||||
v->atlineend = 1;
|
||||
};
|
||||
done = 0;
|
||||
while ((p != NULL) && (done==0)) {
|
||||
p->x = (float) (x + p->xleft);
|
||||
stepon = 1;
|
||||
switch(p->type) {
|
||||
case MUSICLINE:
|
||||
v->inmusic = 1;
|
||||
break;
|
||||
case PRINTLINE:
|
||||
v->inmusic = 0;
|
||||
done = 1;
|
||||
if (!newline) {
|
||||
v->atlineend = 1;
|
||||
stepon = 0;
|
||||
};
|
||||
break;
|
||||
case CLEF:
|
||||
case KEY:
|
||||
case TIME:
|
||||
if (!v->inmusic) {
|
||||
break;
|
||||
};
|
||||
case SINGLE_BAR:
|
||||
case DOUBLE_BAR:
|
||||
case BAR_REP:
|
||||
case REP_BAR:
|
||||
case BAR1:
|
||||
case REP_BAR2:
|
||||
case DOUBLE_REP:
|
||||
case THICK_THIN:
|
||||
case THIN_THICK:
|
||||
*itemspace = *itemspace + p->xleft + p->xright;
|
||||
*items = *items + 1;
|
||||
if (!newline) {
|
||||
done = 1;
|
||||
};
|
||||
break;
|
||||
case REST:
|
||||
case NOTE:
|
||||
tuplefactor = v->tuplefactor;
|
||||
if ((zerotime==1) && (!v->ingrace)) {
|
||||
done = 1;
|
||||
stepon = 0;
|
||||
} else {
|
||||
if ((!v->inchord)&&(!newline)) {
|
||||
done = 1;
|
||||
};
|
||||
*itemspace = *itemspace + p->xleft + p->xright;
|
||||
*items = *items + 1;
|
||||
if (p->type == REST) {
|
||||
arest = p->item;
|
||||
addfract(&v->time, arest->len.num, arest->len.denom);
|
||||
};
|
||||
if ((p->type == NOTE) && (!v->ingrace)) {
|
||||
anote = p->item;
|
||||
notelen = anote->len;
|
||||
|
||||
if (anote->tuplenotes >0) {
|
||||
mulfract(¬elen,tuplefactor.num,tuplefactor.denom);
|
||||
}
|
||||
|
||||
|
||||
addfract(&v->time, notelen.num, notelen.denom);
|
||||
/* printf("%c %d/%d %d/%d\n",anote->pitch,notelen.num,notelen.denom,
|
||||
v->time.num,v->time.denom);
|
||||
*/
|
||||
};
|
||||
};
|
||||
break;
|
||||
case CHORDON:
|
||||
if ((zerotime==1)&&(!v->ingrace)) {
|
||||
done = 1;
|
||||
stepon = 0;
|
||||
} else {
|
||||
v->inchord = 1;
|
||||
};
|
||||
break;
|
||||
case CHORDOFF:
|
||||
if (v->inchord == 1) {
|
||||
v->inchord = 0;
|
||||
if ((!v->ingrace)&&(!newline)) {
|
||||
done = 1;
|
||||
};
|
||||
};
|
||||
break;
|
||||
case GRACEON:
|
||||
v->ingrace = 1;
|
||||
break;
|
||||
case GRACEOFF:
|
||||
v->ingrace = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
if (stepon) {
|
||||
p = p->next;
|
||||
} else {
|
||||
done = 1;
|
||||
};
|
||||
};
|
||||
v->place = p;
|
||||
if (p == NULL) {
|
||||
v->atlineend = 1;
|
||||
};
|
||||
}
|
||||
|
||||
static int gefract(struct fract* a, struct fract* b)
|
||||
/* compare two fractions a greater than or equal to b */
|
||||
/* returns (a >= b) */
|
||||
{
|
||||
if ((a->num*b->denom) >= (b->num*a->denom)) {
|
||||
return(1);
|
||||
} else {
|
||||
return(0);
|
||||
};
|
||||
}
|
||||
|
||||
static int gtfract(struct fract* a, struct fract* b)
|
||||
/* compare two fractions a greater than b */
|
||||
/* returns (a > b) */
|
||||
{
|
||||
if ((a->num*b->denom) > (b->num*a->denom)) {
|
||||
return(1);
|
||||
} else {
|
||||
return(0);
|
||||
};
|
||||
}
|
||||
|
||||
static int spacemultiline(struct fract* mastertime, struct tune* t)
|
||||
/* calculate spacing for one line (but possibly multiple voices) */
|
||||
{
|
||||
int i;
|
||||
int items, thisitems, maxitems;
|
||||
int totalitems;
|
||||
double thiswidth, maxwidth;
|
||||
double totalwidth;
|
||||
double x, gap;
|
||||
int done;
|
||||
struct voice* v;
|
||||
struct fract minlen;
|
||||
|
||||
/* two passes - on the second pass, inter-symbol spacing is */
|
||||
/* known so elements can be given their correct x position */
|
||||
gap = 0.0;
|
||||
for (i=0; i<2; i++) {
|
||||
setfract(mastertime, 0, 1);
|
||||
v = firstitem(&t->voices);
|
||||
while (v != NULL) {
|
||||
v->place = v->lineplace;
|
||||
v->ingrace = 0;
|
||||
v->atlineend = 0;
|
||||
setfract(&v->time, 0, 1);
|
||||
v = nextitem(&t->voices);
|
||||
};
|
||||
done = 0;
|
||||
items = 0;
|
||||
x = 0.0;
|
||||
totalitems = 0;
|
||||
totalwidth = 0.0;
|
||||
/* count up items in a line */
|
||||
while (done == 0) {
|
||||
maxitems = 0;
|
||||
maxwidth = 0.0;
|
||||
/* first do zero-time symbols */
|
||||
v = firstitem(&t->voices);
|
||||
while (v != NULL) {
|
||||
if ((!v->atlineend)&&(gefract(mastertime, &v->time))) {
|
||||
advance(v, 1, &thisitems, &thiswidth, x);
|
||||
if (thisitems > maxitems) {
|
||||
maxitems = thisitems;
|
||||
};
|
||||
if (thiswidth > maxwidth) {
|
||||
maxwidth = thiswidth;
|
||||
};
|
||||
};
|
||||
v = nextitem(&t->voices);
|
||||
};
|
||||
if (maxitems == 0) {
|
||||
/* now try moving forward in time */
|
||||
/* advance all voices at or before mastertime */
|
||||
v = firstitem(&t->voices);
|
||||
while (v != NULL) {
|
||||
if ((!v->atlineend)&&(gefract(mastertime, &v->time))) {
|
||||
advance(v, 2, &thisitems, &thiswidth, x);
|
||||
if (thisitems > maxitems) {
|
||||
maxitems = thisitems;
|
||||
};
|
||||
if (thiswidth > maxwidth) {
|
||||
maxwidth = thiswidth;
|
||||
};
|
||||
};
|
||||
v = nextitem(&t->voices);
|
||||
};
|
||||
/* calculate new mastertime */
|
||||
v = firstitem(&t->voices);
|
||||
setfract(&minlen, 0, 1);
|
||||
done = 1;
|
||||
while (v != NULL) {
|
||||
if (!v->atlineend) {
|
||||
done = 0;
|
||||
if (minlen.num == 0) {
|
||||
setfract(&minlen, v->time.num, v->time.denom);
|
||||
} else {
|
||||
if (gtfract(&minlen, &v->time)) {
|
||||
setfract(&minlen, v->time.num, v->time.denom);
|
||||
};
|
||||
};
|
||||
};
|
||||
v = nextitem(&t->voices);
|
||||
};
|
||||
setfract(mastertime, minlen.num, minlen.denom);
|
||||
};
|
||||
totalitems = totalitems + maxitems;
|
||||
totalwidth = totalwidth + maxwidth;
|
||||
if (maxitems > 0) {
|
||||
x = x + maxwidth + gap;
|
||||
};
|
||||
};
|
||||
/* now calculate inter-symbol gap */
|
||||
if (totalitems > 1) {
|
||||
gap = (scaledwidth - totalwidth)/(totalitems-1);
|
||||
} else {
|
||||
gap = 1.0;
|
||||
};
|
||||
if (gap < 0.0) {
|
||||
event_error("Overfull music line");
|
||||
};
|
||||
if (gap > MAXGAP) {
|
||||
event_error("Underfull music line");
|
||||
gap = MAXGAP;
|
||||
};
|
||||
};
|
||||
if (totalitems == 0) {
|
||||
return(1);
|
||||
} else {
|
||||
return(0);
|
||||
};
|
||||
}
|
||||
|
||||
void spacevoices(struct tune* t)
|
||||
{
|
||||
struct fract mastertime;
|
||||
int donelines;
|
||||
struct voice* v;
|
||||
int items;
|
||||
double x1;
|
||||
|
||||
/* initialize voices */
|
||||
v = firstitem(&t->voices);
|
||||
while (v != NULL) {
|
||||
v->lineplace = v->first;
|
||||
v->inmusic=0;
|
||||
v = nextitem(&t->voices);
|
||||
};
|
||||
donelines = 0;
|
||||
while(donelines == 0) {
|
||||
donelines = spacemultiline(&mastertime, t);
|
||||
v = firstitem(&t->voices);
|
||||
while (v != NULL) {
|
||||
v->lineplace = v->place;
|
||||
advance(v, 3, &items, &x1, 0.0);
|
||||
v->lineplace = v->place;
|
||||
v = nextitem(&t->voices);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
static int spaceline(struct voice* v)
|
||||
/* allocate spare space across the width of a single stave line */
|
||||
/* thereby fixing the x position of all notes and other elements */
|
||||
/* returns 0 when the end of the voice is reached, 1 otherwise */
|
||||
{
|
||||
struct feature* p;
|
||||
double x, lastx = 0.0; /* [SDG] 2020-06-03 */
|
||||
int inmusic, items;
|
||||
double itemspace;
|
||||
double gap;
|
||||
|
||||
itemspace = 0.0;
|
||||
items = 0;
|
||||
inmusic = 0;
|
||||
p = v->place;
|
||||
while ((p != NULL) && (p->type != PRINTLINE)) {
|
||||
switch(p->type) {
|
||||
case MUSICLINE:
|
||||
inmusic = 1;
|
||||
break;
|
||||
case PRINTLINE:
|
||||
inmusic = 0;
|
||||
break;
|
||||
case CLEF:
|
||||
case KEY:
|
||||
case TIME:
|
||||
if (!inmusic) {
|
||||
break;
|
||||
};
|
||||
case SINGLE_BAR:
|
||||
case DOUBLE_BAR:
|
||||
case BAR_REP:
|
||||
case REP_BAR:
|
||||
case BAR1:
|
||||
case REP_BAR2:
|
||||
case DOUBLE_REP:
|
||||
case THICK_THIN:
|
||||
case THIN_THICK:
|
||||
case REST:
|
||||
case NOTE:
|
||||
itemspace = itemspace + p->xleft + p->xright;
|
||||
items = items + 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
p = p->next;
|
||||
};
|
||||
if (items > 1) {
|
||||
gap = (scaledwidth - itemspace)/((double)(items-1));
|
||||
} else {
|
||||
gap = 1.0;
|
||||
};
|
||||
if (gap < 0.0) {
|
||||
event_error("Overfull music line");
|
||||
};
|
||||
if (gap > MAXGAP) {
|
||||
event_error("Underfull music line");
|
||||
gap = MAXGAP;
|
||||
};
|
||||
/* now assign positions */
|
||||
x = 0.0;
|
||||
p = v->place;
|
||||
inmusic = 0;
|
||||
while ((p != NULL) && (p->type != PRINTLINE)) {
|
||||
switch(p->type) {
|
||||
case MUSICLINE:
|
||||
inmusic = 1;
|
||||
break;
|
||||
case PRINTLINE:
|
||||
inmusic = 0;
|
||||
break;
|
||||
case CHORDNOTE:
|
||||
p->x = (float) lastx;
|
||||
break;
|
||||
case CLEF:
|
||||
case KEY:
|
||||
case TIME:
|
||||
if (!inmusic) {
|
||||
break;
|
||||
};
|
||||
case SINGLE_BAR:
|
||||
case DOUBLE_BAR:
|
||||
case BAR_REP:
|
||||
case REP_BAR:
|
||||
case BAR1:
|
||||
case REP_BAR2:
|
||||
case DOUBLE_REP:
|
||||
case THICK_THIN:
|
||||
case THIN_THICK:
|
||||
case REST:
|
||||
case NOTE:
|
||||
x = x + p->xleft;
|
||||
p->x = (float) x;
|
||||
lastx = x;
|
||||
x = x + p->xright + gap;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
p = p->next;
|
||||
};
|
||||
while ((p!=NULL)&&((p->type == PRINTLINE)||(p->type==LINENUM))) {
|
||||
p = p->next;
|
||||
};
|
||||
v->place = p;
|
||||
if (p == NULL) {
|
||||
return(0);
|
||||
} else {
|
||||
return(1);
|
||||
};
|
||||
}
|
||||
|
||||
void monospace(struct tune* t)
|
||||
{
|
||||
int doneline;
|
||||
struct voice* v;
|
||||
|
||||
v = firstitem(&t->voices);
|
||||
while (v != NULL) {
|
||||
doneline = 1;
|
||||
v->place = v->first;
|
||||
while (doneline == 1) {
|
||||
doneline = spaceline(v);
|
||||
};
|
||||
v = nextitem(&t->voices);
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user