2020.10.12

This commit is contained in:
Seymour Shlien
2020-10-12 07:59:07 -04:00
parent 6c9ec6de0e
commit 54a3b903c4
10 changed files with 288 additions and 201 deletions

View File

@@ -49,7 +49,7 @@ Matching:
#define VERSION "1.75 October 01 2020 abcmatch"
#define VERSION "1.75 October 12 2020 abcmatch"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

View File

@@ -13918,3 +13918,23 @@ and applying an appropriate pitchbend to each of these channels.
This may pose a problem for some software which attempts to render the
midi file in music notation.
October 12 2020
James Allwright has made significant improvements to parseabc.c, toabc.c,
and yapstree.c related to repeat checking. In parseabc.c, new functions
were introduced: init_voice_contexts, reset_parser_status,
interpret_voice_label, check_bar_repeats, and check_and_call_bar().
The functions isnumberp(), init_voicecode(), and interpret_voicestring()
have been retired. Reset_parser_status() is called each time a new
X: reference field command is encountered. Check_bar_repeats() replaces
a lot of the code that appears in event_bar() defined in toabc.c and
yapstree.c. parsemusic() calls event_bar indirectly through the
function check_and_call_bar(). Minor changes were made to toabc.c, store.c
and yapstree.c to accommodate the changes to parseabc. In particular,
a new flag repcheck is introduced and connected to parseabc.c as
an extern (in parseabc.h). In addition a new struct (voice_context)
has been introduced in parseabc.h.

View File

@@ -1,10 +1,10 @@
abcMIDI : abc <-> MIDI conversion utilities
midi2abc version 3.46 June 22 2020
abc2midi version 4.42 October 01 2020
abc2abc version 2.10 October 01 2020
yaps version 1.80 October 07 2020
abcmatch version 1.74 October 01 2020
abc2midi version 4.43 October 12 2020
abc2abc version 2.11 October 12 2020
yaps version 1.81 October 12 2020
abcmatch version 1.75 October 12 2020
midicopy version 1.37 October 10 2020
24th January 2002

View File

@@ -824,6 +824,7 @@ void event_octave(num, local)
/* used internally by other routines when octave=N is encountered */
/* in I: or K: fields */
int num;
int local;
{
if (dotune) {
if (pastheader || local) {

View File

@@ -90,10 +90,12 @@ int chorddecorators[DECSIZE];
char decorations[] = ".MLRH~Tuv'OPS"; /* 2020-05-01 */
char *abbreviation[SIZE_ABBREVIATIONS];
int voicecodes = 0;
/* [SS] 2015-03-16 allow 24 voices */
/*char voicecode[16][30]; for interpreting V: string */
char voicecode[24][30]; /*for interpreting V: string */
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];
int voicenum; /* current voice number */
int has_voice_fields = 0;
int decorators_passback[DECSIZE];
/* this global array is linked as an external to store.c and
@@ -329,30 +331,6 @@ skiptospace (p)
*p = *p + 1;
}
int
isnumberp (p)
char **p;
/* returns 1 if positive number, returns 0 if not a positive number */
/* ie -4 or 1A both return 0. This function is needed to get the */
/* voice number. */
{
char **c;
c = p;
while (( **c != ' ') && ( **c != TAB) && **c != '\0')
{
if (( **c >= 0) && (**c <= 9)) /*[SDG] 2020-06-03 */
*c = *c + 1;
else
return 0;
}
return 1;
/* could use isdigit(**c) */
/* is zero a positive number? is V:0 ok? [SS] */
}
int
readnumf (num)
char *num;
@@ -788,72 +766,137 @@ lcase (s)
};
}
void
init_voicecode ()
/* [JA] 2020-10-12 */
void init_voice_contexts (void)
{
int i;
for (i = 0; i < 24; i++) /* [SS} 2015-03-15 */
voicecode[i][0] = 0;
voicecodes = 0;
for (i = 0; i < MAX_VOICES; i++) { /* [SS} 2015-03-15 */
voicecode[i].label[0] = '\0';
voicecode[i].expect_repeat = 0;
voicecode[i].repeat_count = 0;
}
}
/* [JA] 2020-10-12 */
/* called at the start of each tune */
static void reset_parser_status (void)
{
voicenum = 0;
has_voice_fields = 0;
num_voices = 1;
parserinchord = 0;
ingrace = 0;
slur = 0;
init_voice_contexts ();
}
void
print_voicecodes ()
{
int i;
if (voicecodes == 0)
if (num_voices == 0)
return;
printf ("voice mapping:\n");
for (i = 0; i < voicecodes; i++)
for (i = 0; i < num_voices; i++)
{
if (i % 4 == 3)
printf ("\n");
printf ("%s %d ", voicecode[i], i + 1);
printf ("%s %d ", voicecode[i].label, i + 1);
}
printf ("\n");
}
int
interpret_voicestring (char *s)
{
/* if V: is followed by a string instead of a number
* we check to see if we have encountered this string
* before. We assign the number associated with this
* string and add it to voicecode if it was not encountered
* before. If more than 16 distinct strings were encountered
* we report an error -1.
/* [JA] 2020-10-12 */
int interpret_voice_label (char *s, int num)
/* 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.
* The abc standard 2.2 allows strings instead of these numbers to
* represent voices.
* This function should be called with either
* an empty string and a valid num or
* a valid string and num set to 0.
*
* If num is non-zero, we check that it is valid and return it.
* If the number is one above the number of voices currently in use,
* we allocate a new voice.
*
* If num is zero and the string is not empty, we check if string
* has been assigned to one of the existing voices. If not, we
* allocate a new voice and assign the string to it.
*
* If we exceed MAX_VOICES voices, we report an error.
*
* we return a voice number in the range 1 - num_voices
*/
{
int i;
char code[32];
char msg[80]; /* [PHDM] 2012-11-22 */
char *c;
c = readword (code, s);
/* [PHDM] 2012-11-22 */
if (*c != '\0' && *c != ' ' && *c != ']')
if (num > 0)
{
if (num > num_voices + 1)
{
char error_message[80];
snprintf(error_message, 80, "V:%d out of sequence, treating as V:%d",
num, num_voices);
event_warning(error_message);
num = num_voices + 1;
}
/* declaring a new voice */
if (num == num_voices + 1)
{
if (num_voices >= MAX_VOICES)
{
event_warning("Number of available voices exceeded");
return 1;
}
num_voices = num_voices + 1;
voicecode[num_voices - 1].label[0] = '\0';
}
return num;
}
/* [PHDM] 2012-11-22 */
if (*c != '\0' && *c != ' ' && *c != ']') {
sprintf (msg, "invalid character `%c' in Voice ID", *c);
event_error (msg);
}
/* [PHDM] 2012-11-22 */
if (code[0] == '\0')
return 0;
if (voicecodes == 0)
{
strcpy (voicecode[voicecodes], code);
voicecodes++;
return voicecodes;
event_warning("Empty V: field, treating as V:1");
return 1;
}
for (i = 0; i < voicecodes; i++)
if (stringcmp (code, voicecode[i]) == 0)
return (i + 1);
if ((voicecodes + 1) > 23) /* [SS] 2015-03-16 */
return -1;
strcpy (voicecode[voicecodes], code);
voicecodes++;
return voicecodes;
/* Has supplied label been used for one of the existing voices ? */
if (has_voice_fields)
{
for (i = 0; i < num_voices; i++) {
if (strcmp (code, voicecode[i].label) == 0) {
return i + 1;
}
}
}
/* if we have got here, we have a new voice */
if ((num_voices + 1) > MAX_VOICES) {/* [SS] 2015-03-16 */
event_warning("Number of available voices exceeded");
return 1;
}
/* First V: field is a special case. We are already on voice 1,
* so we don't increment the number of voices, but we will set
* status->has_voice_fields on returning from this function.
*/
if (has_voice_fields)
{
num_voices++;
}
strncpy (voicecode[num_voices - 1].label, code, 31);
return num_voices;
}
/* The following three functions parseclefs, parsetranspose,
@@ -1479,22 +1522,14 @@ parsevoice (s)
vparams.other[0] = '\0'; /* [SS] 2011-04-18 */
skipspace (&s);
if (isnumberp (&s) == 1)
{
num = 0;
if (isdigit(*s)) { /* [JA] 2020-10-12 */
num = readnump (&s);
}
else
{
num = interpret_voicestring (s);
if (num == 0)
event_error ("No voice number or string in V: field");
if (num == -1)
{
event_error ("More than 16 voices encountered in V: fields");
num = 0;
}
num = interpret_voice_label (s, num);
has_voice_fields = 1;
skiptospace (&s);
};
voicenum = num;
skipspace (&s);
while (*s != '\0')
{
@@ -2115,9 +2150,14 @@ parsefield (key, field)
{
event_error ("second X: field in header");
};
if (inbody)
{
/* [JA] 2020-10-14 */
event_error ("Missing blank line before new tune");
}
event_refno (x);
ignore_line =0; /* [SS] 2017-04-12 */
init_voicecode (); /* [SS] 2011-01-01 */
reset_parser_status(); /* [JA] 2020-10-12 */
inhead = 1;
inbody = 0;
parserinchord = 0;
@@ -2376,6 +2416,99 @@ print_inputline ()
printf ("\n");
}
/* [JA] 2020-10-12 */
/* Look for problems in the use of repeats */
static void check_bar_repeats (int bar_type, char *replist)
{
voice_context_t *cv = &voicecode[voicenum];
switch (bar_type) {
case SINGLE_BAR:
break;
case DOUBLE_BAR:
break;
case THIN_THICK:
break;
case THICK_THIN:
break;
case BAR_REP:
if (cv->expect_repeat) {
event_warning ("Expecting repeat, found |:");
};
cv->expect_repeat = 1;
cv->repeat_count = cv->repeat_count + 1;
break;
case REP_BAR:
if (!cv->expect_repeat) {
char error_message[80];
if (cv->repeat_count == 0)
{
snprintf(error_message, 80, "Missing repeat at start ? Unexpected :|%s found", replist);
event_warning (error_message);
}
else
{
snprintf(error_message, 80, "Unexpected :|%s found", replist);
event_warning (error_message);
}
};
cv->expect_repeat = 0;
cv->repeat_count = cv->repeat_count + 1;
break;
case BAR1:
if (!cv->expect_repeat) {
if (cv->repeat_count == 0)
{
event_warning ("Missing repeat at start ? found |1");
}
else
{
event_warning ("found |1 in non-repeat section");
}
};
break;
case REP_BAR2:
if (!cv->expect_repeat) {
if (cv->repeat_count == 0)
{
event_warning ("Missing repeat at start ? found :|2");
}
else
{
event_warning ("No repeat expected, found :|2");
}
};
cv->expect_repeat = 0;
cv->repeat_count = cv->repeat_count + 1;
break;
case DOUBLE_REP:
if (!cv->expect_repeat) {
if (cv->repeat_count == 0)
{
event_warning ("Missing repeat at start ? found ::");
}
else
{
event_warning ("No repeat expected, found ::");
}
};
cv->expect_repeat = 1;
cv->repeat_count = cv->repeat_count + 1;
break;
};
}
/* [JA] 2020-10-12 */
static void check_and_call_bar(int bar_type, char *replist)
{
if (repcheck)
{
check_bar_repeats (bar_type, replist);
}
event_bar (bar_type, replist);
}
void
parsemusic (field)
char *field;
@@ -2459,20 +2592,20 @@ parsemusic (field)
switch (*p)
{
case ':':
event_bar (BAR_REP, "");
check_and_call_bar (BAR_REP, "");
p = p + 1;
break;
case '|':
event_bar (DOUBLE_BAR, "");
check_and_call_bar (DOUBLE_BAR, "");
p = p + 1;
break;
case ']':
event_bar (THIN_THICK, "");
check_and_call_bar (THIN_THICK, "");
p = p + 1;
break;
default:
p = getrep (p, playonrep_list);
event_bar (SINGLE_BAR, playonrep_list);
check_and_call_bar (SINGLE_BAR, playonrep_list);
};
break;
case ':':
@@ -2480,20 +2613,20 @@ parsemusic (field)
switch (*p)
{
case ':':
event_bar (DOUBLE_REP, "");
check_and_call_bar (DOUBLE_REP, "");
p = p + 1;
break;
case '|':
p = p + 1;
p = getrep (p, playonrep_list);
event_bar (REP_BAR, playonrep_list);
check_and_call_bar (REP_BAR, playonrep_list);
if (*p == ']')
p = p + 1; /* [SS] 2013-10-31 */
break;
/* [JM] 2018-02-22 dotted bar line ... this is legal */
default:
/* [SS] 2018-02-08 introducing DOTTED_BAR */
event_bar (DOTTED_BAR,"");
check_and_call_bar (DOTTED_BAR,"");
};
break;
case ' ':
@@ -2558,9 +2691,9 @@ parsemusic (field)
{
case '|':
p = p + 1;
event_bar (THICK_THIN, "");
check_and_call_bar (THICK_THIN, "");
if (*p == ':') { /* [SS] 2015-04-13 [SDG] 2020-06-04 */
event_bar (BAR_REP, "");
check_and_call_bar (BAR_REP, "");
p = p + 1;
}
break;
@@ -2596,7 +2729,7 @@ parsemusic (field)
/*if (!inchordflag && *p == '|') { [SS] 2018-12-21 not THICK_THIN bar line*/
if (!parserinchord && *p == '|') { /* [SS] 2019-06-06 not THICK_THIN bar line*/
p = p + 1; /* skip over | */
event_bar (THIN_THICK, "");}
check_and_call_bar (THIN_THICK, "");}
else {
readlen (&chord_n, &chord_m, &p); /* [SS] 2019-06-06 */
event_chordoff (chord_n, chord_m);

View File

@@ -32,12 +32,22 @@ struct voice_params {
char other[V_STRLEN+1]; /* [SS] 2011-04-18 */
};
typedef struct voice_context {
char label[31];
int expect_repeat;
int repeat_count;
} voice_context_t;
#define MAX_VOICES 30
/* holds a fraction */
struct fraction {
int num;
int denom;
};
extern int repcheck; /* allows backend to enable/disable repeat checking */
extern voice_context_t voicecode[MAX_VOICES];
#ifndef KANDR
extern int readnump(char **p);

View File

@@ -185,7 +185,7 @@ int main()
*/
#define VERSION "4.42 Ocober 01 2020 abc2midi"
#define VERSION "4.43 Ocober 12 2020 abc2midi"
/* enables reading V: indication in header */
#define XTEN1 1
@@ -892,6 +892,10 @@ char **filename;
} else {
check = 0;
};
/* disable repeat checking because abc2midi does its own workaround
* attempting to fix various repeat errors.
*/
repcheck = 0;
/* look for filename-from-tune-titles option */
namelimit = 252;
titlenames = 0;

View File

@@ -151,7 +151,6 @@ struct voice {
struct fract barcount;
int barno;
int barchecking;
int expect_repeat;
int brokentype, brokenmult, brokenpending;
int tiespending;
struct feature* tie_place[MAX_TIES];

55
toabc.c
View File

@@ -21,7 +21,7 @@
/* back-end for outputting (possibly modified) abc */
#define VERSION "2.10 October 06 2020 abc2abc"
#define VERSION "2.11 October 12 2020 abc2abc"
/* for Microsoft Visual C++ 6.0 or higher */
#ifdef _MSC_VER
@@ -66,7 +66,7 @@ struct fract chordfactor; /* factor of the first note in a chord [PHDM] 2013-03-
struct fract breakpoint; /* used to break bar into beamed sets of notes */
int barno; /* number of bar within tune */
int newspacing; /* was -s option selected ? */
int barcheck, repcheck; /* indicate -b and -r options selected */
int barcheck; /* indicate -b and -r options selected */
int echeck; /* was error-checking turned off ? (-e option) */
int newbreaks; /* was -n option selected ? */
int nodouble_accidentals;
@@ -105,8 +105,6 @@ char* clef = ""; /* [SS] 2020-01-22 */
extern int nokey; /* signals no key signature assumed */
extern int nokeysig; /* signals -nokeys or -nokeysf option */
extern int voicecodes ; /* from parseabc.c */
extern char voicecode[16][30]; /*for interpreting V: string */
struct voicetype { /* information needed for each voice */
int number; /* voice number from V: field */
@@ -115,7 +113,6 @@ struct voicetype { /* information needed for each voice */
struct abctext* currentline;
int bars_remaining;
int bars_complete;
int expect_repeat; /* [SS] 2018-12-01 */
int drumchan;
} voice[MAX_VOICES];
int voicecount, this_voice, next_voice;
@@ -1206,7 +1203,6 @@ int num;
voice[voice_index].bars_complete = 0;
voice[voice_index].bars_remaining = bars_per_line;
voice[voice_index].drumchan = 0;
voice[voice_index].expect_repeat = -1; /* [SS] 2018-12-01 */
};
voice[voice_index].currentline = NULL;
return(voice_index);
@@ -1236,9 +1232,11 @@ struct voice_params *vp;
};
};
};
if (strlen(s) == 0) {
if(voicecodes >= n) emit_string_sprintf("V:%s",voicecode[n-1]);
else emit_int_sprintf("V:%d", n);
if (strlen(voicecode[n-1].label) > 0) {
emit_string_sprintf("V:%s",voicecode[n-1].label);
} else {
emit_int_sprintf("V:%d", n);
}
if (vp->gotclef) {sprintf(output," clef=%s", vp->clefname);
emit_string(output);}
if (vp->gotoctave) {sprintf(output," octave=%d", vp->octave);
@@ -1253,21 +1251,7 @@ struct voice_params *vp;
emit_string(output);}
if( vp->gotother ) { sprintf(output, " %s", vp->other);
emit_string(output);} /* [SS] 2011-04-18 */
} else {
if(voicecodes >= n) emit_string_sprintf("V:%s",voicecode[n-1]);
emit_int_sprintf("V:%d ", n);
if (vp->gotclef) {sprintf(output," clef=%s", vp->clefname);
emit_string(output);}
if (vp->gotoctave) {sprintf(output," octave=%d", vp->octave);
emit_string(output);}
if (vp->gottranspose) {sprintf(output," transpose=%d", vp->transpose);
emit_string(output);}
if (vp->gotname) {sprintf(output," name=%s", vp->namestring);
emit_string(output);}
if( vp->gotmiddle ) { sprintf(output, " middle=%s", vp->middlestring);
emit_string(output);}
if( vp->gotother ) { sprintf(output, " %s", vp->other);
emit_string(output);} /* [SS] 2011-04-18 */
if (strlen(s) != 0) {
emit_string(s);
};
inmusic = 0;
@@ -1426,8 +1410,6 @@ static void start_tune()
count.denom = 1;
barno = 0;
tuplenotes = 0;
/* expect_repeat is now a voice struct variable [SS] 2018-12-01 */
/* expect_repeat = -1; repeat from start may occur [J-FM] 2012-06-04 */
inlinefield = 0;
if (barlen.num == 0) {
/* generate missing time signature */
@@ -1741,39 +1723,18 @@ char* replist;
break;
case BAR_REP:
emit_string("|:");
if (voice[this_voice].expect_repeat > 0 && repcheck)
{
/* no error if first repeat [J-FM] 2012-06-04 */
event_error("Expecting repeat, found |:");
};
voice[this_voice].expect_repeat = 1;
break;
case REP_BAR:
emit_string_sprintf(":|%s", replist);
if ((!voice[this_voice].expect_repeat) && (repcheck)) {
event_warning("No repeat expected, found :|");
};
voice[this_voice].expect_repeat = 0;
break;
case BAR1:
emit_string("|1");
if ((!voice[this_voice].expect_repeat) && (repcheck)) {
event_warning("found |1 in non-repeat section");
};
break;
case REP_BAR2:
emit_string(":|2");
if ((!voice[this_voice].expect_repeat) && (repcheck)) {
event_warning("No repeat expected, found :|2");
};
voice[this_voice].expect_repeat = 0;
break;
case DOUBLE_REP:
emit_string("::");
if ((voice[this_voice].expect_repeat) && (repcheck)) {
event_error("No repeat expected, found ::");
};
voice[this_voice].expect_repeat = 1;
break;
};
if ((count.num*barlen.denom != barlen.num*count.denom) &&

View File

@@ -22,7 +22,7 @@
/* yapstree.c - back-end for abc parser. */
/* generates a data structure suitable for typeset music */
#define VERSION "1.80 October 07 2020 yaps"
#define VERSION "1.81 October 12 2020 yaps"
#include <stdio.h>
#ifdef USE_INDEX
#define strchr index
@@ -64,7 +64,6 @@ char outputroot[256];
char matchstring[256];
int fileopen;
int repcheck;
int xinhead;
int xinbody;
int suppress;
@@ -792,7 +791,6 @@ static struct voice* newvoice(int n)
v->inslur = 0;
v->ingrace = 0;
v->inchord = 0;
v->expect_repeat = 0;
v->tuplenotes = 0;
v->thistuple = NULL;
v->tuple_count = 0;
@@ -2195,45 +2193,6 @@ char* playonrep_list;
checkbar(type); /* increment bar number if bar complete */
/* [SS] 2015-11-15 * changed (void*) to (int *) */
addfeature(type, (int *)cv->barno); /* save bar number */
switch(type) {
case SINGLE_BAR:
break;
case DOUBLE_BAR:
break;
case THIN_THICK:
break;
case THICK_THIN:
break;
case BAR_REP:
if ((cv->expect_repeat) && (repcheck)) {
event_error("Expecting repeat, found |:");
};
cv->expect_repeat = 1;
break;
case REP_BAR:
if ((!cv->expect_repeat) && (repcheck)) {
event_error("No repeat expected, found :|");
};
cv->expect_repeat = 0;
break;
case BAR1:
if ((!cv->expect_repeat) && (repcheck)) {
event_error("found |1 in non-repeat section");
};
break;
case REP_BAR2:
if ((!cv->expect_repeat) && (repcheck)) {
event_error("No repeat expected, found :|2");
};
cv->expect_repeat = 0;
break;
case DOUBLE_REP:
if ((!cv->expect_repeat) && (repcheck)) {
event_error("No repeat expected, found ::");
};
cv->expect_repeat = 1;
break;
};
if ((playonrep_list != NULL) && (strlen(playonrep_list) > 0)) {
event_playonrep(playonrep_list);
};