mirror of
https://github.com/sshlien/abcmidi.git
synced 2025-12-06 06:55:06 +00:00
2020.12.10
This commit is contained in:
403
parseabc.c
403
parseabc.c
@@ -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(¤t_voice->timesig, &master_timesig);
|
||||
copy_clef(¤t_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, ×ig);
|
||||
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, ×ig);
|
||||
}
|
||||
if (inbody) {
|
||||
/* update timesig in current voice */
|
||||
voice_context_t *current_voice;
|
||||
|
||||
current_voice = &voicecode[voicenum - 1];
|
||||
copy_timesig(¤t_voice->timesig, ×ig);
|
||||
}
|
||||
event_timesig (×ig);
|
||||
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
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user