2020.12.10

This commit is contained in:
Seymour Shlien
2020-12-10 15:42:29 -05:00
parent dbf87e070c
commit eefa44b8bd
13 changed files with 789 additions and 281 deletions

View File

@@ -95,6 +95,10 @@ int num_voices = 0; /* [JA] 2020-10-12 */
int repcheck = 1; /* enables/ disables repeat checking */
/* abc2midi disables repeat checking because it does its own thing */
voice_context_t voicecode[MAX_VOICES];
timesig_details_t master_timesig; /* [JA] 2020-12-10 */
cleftype_t master_clef;
int has_timesig;
int master_unitlen; /* L: field value is 1/unitlen */
int voicenum; /* current voice number */
int has_voice_fields = 0;
@@ -405,68 +409,138 @@ readsnump (p)
}
}
void
readsig (a, b, sig)
int *a, *b;
char **sig;
/* read time signature (meter) from M: field */
/* [JA] 2020-12-10 */
int check_power_of_two(int denom)
{
int t;
char c; /* [SS] 2015-08-19 */
char error_message[80];
t = denom;
while (t > 1) {
if (t % 2 != 0) {
snprintf(error_message, 80, "%d b is not a power of 2", denom);
event_error (error_message);
return 0;
} else {
t = t / 2;
}
}
return denom;
}
/* [JA] 2020-12-10 */
/* read the numerator of a time signature in M: field
*
* abc standard 2.2 allows M:(a + b + c + ...)/d
* This indicates how note lenths within a bar are to be grouped.
* abc standard also allows a+b+c/d to mean the same thing but this
* goes against the convention that division takes precendence
* over addition i.e. a+b+c/d normally means a + b + (c/d).
*/
static int read_complex_has_timesig(char **place, timesig_details_t *timesig)
{
int n;
int total;
int count;
int has_bracket = 0;
if (**place == '(') {
*place = *place + 1;
has_bracket = 1;
skipspace(place);
}
count = 0;
total = 0;
skipspace(place);
while ((**place != '\0') && (isdigit(**place))) {
n = readnump(place);
timesig->complex_values[count] = n;
total = total + n;
count = count + 1;
if (count > 8) {
event_error("Too many parts to complex time (maximum 8)");
return 0;
}
skipspace(place);
if (**place == '+') {
*place = *place + 1;
skipspace(place);
}
}
if (**place == ')') {
*place = *place + 1; /* advance over ')' */
skipspace(place);
if (!has_bracket) {
event_warning("Missing ( in complex time");
}
has_bracket = 0;
}
if (has_bracket) {
event_warning("Missing ) in complex time");
}
/* we have reached the end of the numerator */
timesig->num_values = count;
timesig->num = total;
if (timesig->num_values == 1)
{
timesig->type = TIMESIG_NORMAL;
} else {
timesig->type = TIMESIG_COMPLEX;
}
return 1;
}
/* read time signature (meter) from M: field */
void readsig (char **sig, timesig_details_t *timesig)
/* upgraded [JA] 2020-12-10 */
{
int valid_num;
if ((strncmp (*sig, "none", 4) == 0) ||
(strncmp (*sig, "None", 4) == 0)) {
timesig->num = 4;
timesig->denom = 4;
timesig->type = TIMESIG_FREE_METER;
return;
}
/* [SS] 2012-08-08 cut time (C| or c|) is 2/2 not 4/4 */
if ((*(*sig + 1) == '|') && ((**sig == 'C') || (**sig == 'c')))
{
*a = 2;
*b = 2;
return;
}
if (((**sig == 'C') || (**sig == 'c')) &&
(*(*sig + 1) == '|')) {
timesig->num = 2;
timesig->denom = 2;
timesig->type = TIMESIG_CUT;
return;
}
if ((**sig == 'C') || (**sig == 'c')) {
timesig->num = 4;
timesig->denom = 4;
timesig->type = TIMESIG_COMMON;
return;
}
valid_num = read_complex_has_timesig(sig, timesig);
if (!valid_num) {
/* An error message will have been generated by read_complex_has_timesig */
timesig->num = 4;
timesig->denom = 4;
timesig->type = TIMESIG_FREE_METER;
return;
}
if ((**sig == 'C') || (**sig == 'c'))
{
*a = 4;
*b = 4;
return;
};
*a = readnump (sig);
/* [SS] 2015-08-19 */
while ((int) **sig == '+') {
if ((int)**sig != '/') {
event_warning ("No / found, assuming denominator of 1");
timesig->denom = 1;
} else {
*sig = *sig + 1;
c = readnump (sig);
*a = *a + c;
skipspace(sig);
if (!isdigit(**sig)) {
event_warning ("Number not found for M: denominator");
}
if ((int) **sig != '/')
{
event_error ("Missing / ");
}
else
{
*sig = *sig + 1;
};
*b = readnump (sig);
if ((*a == 0) || (*b == 0))
{
event_error ("Expecting fraction in form A/B");
}
else
{
t = *b;
while (t > 1)
{
if (t % 2 != 0)
{
event_error ("divisor must be a power of 2");
t = 1;
*b = 0;
}
else
{
t = t / 2;
};
};
};
timesig->denom = readnump (sig);
}
if ((timesig->num == 0) || (timesig->denom == 0)) {
event_error ("Expecting fraction in form A/B");
} else {
timesig->denom = check_power_of_two(timesig->denom);
}
}
void
@@ -497,19 +571,32 @@ readlen (a, b, p)
};
};
};
t = *b;
while (t > 1)
{
if (t % 2 != 0)
{
event_warning ("divisor not a power of 2");
t = 1;
}
else
{
t = t / 2;
};
};
*b = check_power_of_two(*b);
}
/* [JA] 2020-12-10 */
static void read_L_unitlen(int *num, int *denom, char **place)
{
if (!isdigit(**place)) {
event_warning("No digit at the start of L: field");
}
*num = readnump (place);
if (*num == 0) {
*num = 1;
}
if ((int)**place != '/') {
event_error ("Missing / ");
*denom = 1;
} else {
*place = *place + 1;
skipspace(place);
*denom = readnump (place);
}
if ((*num == 0) || (*denom == 0)) {
event_error ("Expecting fraction in form A/B");
} else {
*denom = check_power_of_two(*denom);
}
}
void
@@ -661,6 +748,16 @@ lcase (s)
};
}
/* initialize a timesig structure to default values */
void init_timesig(timesig_details_t *timesig)
{
timesig->type = TIMESIG_FREE_METER;
timesig->num = 4;
timesig->denom = 4;
timesig->complex_values[0] = 4;
timesig->num_values = 1;
}
/* [JA] 2020-10-12 */
void init_voice_contexts (void)
{
@@ -677,11 +774,32 @@ void init_voice_contexts (void)
}
}
/* copy one timesig_details_t struct to another [JA] 2020-12-10 */
void copy_timesig(timesig_details_t *destination, timesig_details_t *source)
{
int i;
destination->type = source->type;
destination->num = source->num;
destination->denom = source->denom;
for (i = 0; i < 8; i++)
{
destination->complex_values[i] = source->complex_values[i];
}
destination->num_values = source->num_values;
}
/* [JA] 2020-10-12 */
/* called at the start of each tune */
static void reset_parser_status (void)
{
voicenum = 0;
cleftype_t default_clef;
init_timesig(&master_timesig);
get_standard_clef ("treble", &master_clef); /* default to treble clef */
has_timesig = 0;
master_unitlen = -1;
voicenum = 1;
has_voice_fields = 0;
num_voices = 1;
parserinchord = 0;
@@ -708,7 +826,7 @@ print_voicecodes ()
}
/* [JA] 2020-10-12 */
int interpret_voice_label (char *s, int num)
int interpret_voice_label (char *s, int num, int *is_new)
/* We expect a numeric value indicating the voice number.
* The assumption is that these will ocuur in the order in which voices
* appear, so that we have V:1, V:2, ... V:N if there are N voices.
@@ -756,6 +874,7 @@ int interpret_voice_label (char *s, int num)
/* declaring a new voice */
if (num == num_voices + 1)
{
*is_new = 1;
if (num_voices >= MAX_VOICES)
{
event_warning("Number of available voices exceeded");
@@ -763,6 +882,9 @@ int interpret_voice_label (char *s, int num)
}
num_voices = num_voices + 1;
voicecode[num_voices - 1].label[0] = '\0';
} else {
/* we are using a previously declared voice */
*is_new = 0;
}
return num;
}
@@ -798,7 +920,10 @@ int interpret_voice_label (char *s, int num)
*/
if (has_voice_fields)
{
*is_new = 1;
num_voices++;
} else {
*is_new = 0; /* we have already started as voice 1 */
}
strncpy (voicecode[num_voices - 1].label, code, 31);
return num_voices;
@@ -1222,7 +1347,12 @@ parsekey (str)
parsed = parseclef (&s, word, &gotclef, clefstr, &newclef, &cgotoctave, &coctave);
if (gotclef) {
/* make clef an attribute of current voice */
copy_clef (&voicecode[voicenum - 1].clef, &newclef);
if (inhead) {
copy_clef (&master_clef, &newclef);
}
if (inbody){
copy_clef (&voicecode[voicenum - 1].clef, &newclef);
}
}
/* parseclef also scans the s string using readword(), placing */
/* the next token into the char array word[]. */
@@ -1420,6 +1550,15 @@ parsekey (str)
return (gotkey);
}
static void set_voice_from_master(int voice_num)
{
voice_context_t *current_voice;
current_voice = &voicecode[voice_num - 1];
copy_timesig(&current_voice->timesig, &master_timesig);
copy_clef(&current_voice->clef, &master_clef);
current_voice->unitlen = master_unitlen;
}
void
parsevoice (s)
@@ -1430,6 +1569,7 @@ parsevoice (s)
char word[64]; /* 2017-10-11 */
int parsed;
int coctave, cgotoctave;
int is_new = 0;
vparams.transpose = 0;
vparams.gottranspose = 0;
@@ -1449,7 +1589,12 @@ parsevoice (s)
if (isdigit(*s)) { /* [JA] 2020-10-12 */
num = readnump (&s);
}
num = interpret_voice_label (s, num);
num = interpret_voice_label (s, num, &is_new);
if (is_new) {
/* declaring voice for the first time.
* initialize with values set in the tune header */
set_voice_from_master(num);
}
has_voice_fields = 1;
skiptospace (&s);
voicenum = num;
@@ -2053,6 +2198,45 @@ free_abbreviations ()
};
}
/* function to resolve unit note length when the
* L: field is missing in the header [JA] 2020-12-10
*
* From the abc standard 2.2:
* If there is no L: field defined, a unit note length is set by default,
* based on the meter field M:. This default is calculated by computing
* the meter as a decimal: if it is less than 0.75 the default unit note
* length is a sixteenth note; if it is 0.75 or greater, it is an eighth
* note. For example, 2/4 = 0.5, so, the default unit note length is a
* sixteenth note, while for 4/4 = 1.0, or 6/8 = 0.75, or 3/4= 0.75,
* it is an eighth note. For M:C (4/4), M:C| (2/2) and M:none (free meter),
* the default unit note length is 1/8.
*
*/
static void resolve_unitlen()
{
if (master_unitlen == -1)
{
if (has_timesig == 0)
{
event_default_length(8);
master_unitlen = 8;
}
else
{
if (((4 * master_timesig.num)/master_timesig.denom) >= 3)
{
event_default_length(8);
master_unitlen = 8;
}
else
{
event_default_length(16);
master_unitlen = 16;
}
}
}
}
void
parsefield (key, field)
char key;
@@ -2115,9 +2299,18 @@ parsefield (key, field)
switch (key)
{
case 'K':
if (inhead)
{
/* First K: is the end of the header and the start of the body.
* make sure we set up default for unit length
* if L: fields was missing in the header.
*/
resolve_unitlen();
/* set voice parameters using values from header */
set_voice_from_master(1);
}
foundkey = parsekey (place);
if (inhead || inbody)
{
if (inhead || inbody) {
if (foundkey)
{
inbody = 1;
@@ -2138,7 +2331,7 @@ parsefield (key, field)
break;
case 'M':
{
int num, denom;
timesig_details_t timesig;
/* strncpy (timesigstring, place, 16); [SS] 2011-08-19 */
#ifdef NO_SNPRINT
@@ -2146,36 +2339,34 @@ parsefield (key, field)
#else
snprintf(timesigstring,sizeof(timesigstring),"%s",place); /* [SEG] 2020-06-07 */
#endif
if (strncmp (place, "none", 4) == 0)
/* converts 'M: none' to 'M: 4/4' otherwise a warning
* is returned if not a fraction [SS] */
{
event_timesig (4, 4, 0);
}
else
{
readsig (&num, &denom, &place);
if ((*place == 's') || (*place == 'l'))
{
event_error ("s and l in M: field not supported");
};
if ((num != 0) && (denom != 0))
{
/* [code contributed by Larry Myerscough 2015-11-5]
* Specify checkbars = 1 for numeric time signature
* or checkbars = 2 for 'common' time signature to
* remain faithful to style of input abc file.
*/
event_timesig (num, denom, 1 + ((*place == 'C') || (*place == 'c')));
};
};
break;
};
readsig (&place, &timesig);
if ((*place == 's') || (*place == 'l')) {
event_error ("s and l in M: field not supported");
};
if ((timesig.num == 0) || (timesig.denom == 0)) {
event_warning ("Invalid time signature ignored");
} else {
if (inhead) {
/* copy timesig into master_timesig */
copy_timesig(&master_timesig, &timesig);
}
if (inbody) {
/* update timesig in current voice */
voice_context_t *current_voice;
current_voice = &voicecode[voicenum - 1];
copy_timesig(&current_voice->timesig, &timesig);
}
event_timesig (&timesig);
has_timesig = 1;
}
}
break;
case 'L':
{
int num, denom;
readsig (&num, &denom, &place);
read_L_unitlen(&num, &denom, &place);
if (num != 1)
{
event_error ("Default length must be 1/X");
@@ -2185,6 +2376,16 @@ parsefield (key, field)
if (denom > 0)
{
event_length (denom);
if (inhead)
{
master_unitlen = denom;
}
if (inbody) {
voice_context_t *current_voice;
current_voice = &voicecode[voicenum - 1];
current_voice->unitlen = denom;
}
}
else
{