commit 93df4ecc41846e02c500324862682557b87edca4
parent 29335272dd54eacceb81471dad2554a300ef5423
Author: nibo <nibo@relim.de>
Date: Wed, 21 Aug 2024 10:47:15 +0200
Improve chord parsing
Parsing with nashville or roman naming system
isn't finished.
Diffstat:
5 files changed, 139 insertions(+), 13 deletions(-)
diff --git a/chordpro.c b/chordpro.c
@@ -1353,6 +1353,24 @@ static struct ChoChord *cho_chord_new(void)
return chord;
}
+/* INFO: copy every field except for 'style' */
+static void cho_chord_complete(struct ChoChord *first, struct ChoChord *second)
+{
+ first->name = strdup(second->name);
+ first->is_canonical = second->is_canonical;
+ first->qual = second->qual;
+ if (second->root) {
+ first->root = strdup(second->root);
+ }
+ if (second->ext) {
+ first->ext = strdup(second->ext);
+ }
+ if (second->bass) {
+ first->bass = strdup(second->bass);
+ }
+}
+
+
static void cho_chord_free(struct ChoChord *chord)
{
cho_style_free(chord->style);
@@ -1404,6 +1422,20 @@ static char *cho_chord_qualifier_strip(const char *str)
return strdup(str);
}
+static const char *cho_chord_qualifier_to_string(enum ChordQualifier qual)
+{
+ switch (qual) {
+ case CQ_MIN:
+ return "m";
+ case CQ_AUG:
+ return "+";
+ case CQ_DIM:
+ return "°";
+ default:
+ return "";
+ }
+}
+
static int cho_chord_qualifier_and_extension_parse(const char *str, struct ChoChord *chord)
{
int i;
@@ -1437,6 +1469,10 @@ static int cho_chord_qualifier_and_extension_parse(const char *str, struct ChoCh
chord->qual = CQ_DIM;
return 1;
}
+ if (str_starts_with(str, "ø")) {
+ chord->qual = CQ_DIM;
+ return 1;
+ }
// TODO: What about 'ø', 'h', 'h7' and 'h9'?
// TODO: What about extensions after 'aug', '+', 'dim', '0'?
return 0;
@@ -1508,6 +1544,53 @@ static struct ChoChord *cho_chord_parse(const char *str)
return chord;
}
+char *cho_chord_name_generate(struct ChoChord *chord)
+{
+ if (chord->is_canonical) {
+ int n = 0;
+ int i;
+ char *name = NULL;
+ size_t name_len = 0;
+ name_len += strlen(chord->root);
+ name = realloc(name, name_len * sizeof(char));
+ for (i = 0; chord->root[i]; i++) {
+ name[n] = chord->root[i];
+ n++;
+ }
+ const char *qual = cho_chord_qualifier_to_string(chord->qual);
+ name_len += strlen(qual);
+ name = realloc(name, name_len * sizeof(char));
+ for (i = 0; qual[i]; i++) {
+ name[n] = qual[i];
+ n++;
+ }
+ if (chord->ext) {
+ name_len += strlen(chord->ext);
+ name = realloc(name, name_len * sizeof(char));
+ for (i = 0; chord->ext[i]; i++) {
+ name[n] = chord->ext[i];
+ n++;
+ }
+ }
+ if (chord->bass) {
+ name_len++;
+ name_len += strlen(chord->bass);
+ name = realloc(name, name_len * sizeof(char));
+ name[n] = '/';
+ n++;
+ for (i = 0; chord->bass[i]; i++) {
+ name[n] = chord->bass[i];
+ n++;
+ }
+ }
+ name_len++;
+ name = realloc(name, name_len * sizeof(char));
+ name[n] = 0;
+ return name;
+ }
+ return strdup(chord->name);
+}
+
static struct ChoAnnotation *cho_annotation_new(void)
{
struct ChoAnnotation *annot = malloc(sizeof(struct ChoAnnotation));
@@ -2394,20 +2477,10 @@ struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config)
chord_pos = cho_line_compute_chord_position(songs[so]->sections[se]->lines[li], ly, te);
songs[so]->sections[se]->lines[li]->text_above[c]->position = chord_pos;
tmp_chord = cho_chord_parse(chord);
- songs[so]->sections[se]->lines[li]->text_above[c]->u.chord->name = strdup(tmp_chord->name);
- songs[so]->sections[se]->lines[li]->text_above[c]->u.chord->is_canonical = tmp_chord->is_canonical;
+ cho_chord_complete(songs[so]->sections[se]->lines[li]->text_above[c]->u.chord, tmp_chord);
if (!songs[so]->sections[se]->lines[li]->text_above[c]->u.chord->is_canonical) {
fprintf(stderr, "INFO: Didn't recognize the chord '%s' in line %d.\n", songs[so]->sections[se]->lines[li]->text_above[c]->u.chord->name, line_number);
}
- if (songs[so]->sections[se]->lines[li]->text_above[c]->u.chord->root) {
- songs[so]->sections[se]->lines[li]->text_above[c]->u.chord->root = strdup(tmp_chord->root);
- }
- if (songs[so]->sections[se]->lines[li]->text_above[c]->u.chord->ext) {
- songs[so]->sections[se]->lines[li]->text_above[c]->u.chord->ext = strdup(tmp_chord->ext);
- }
- if (songs[so]->sections[se]->lines[li]->text_above[c]->u.chord->bass) {
- songs[so]->sections[se]->lines[li]->text_above[c]->u.chord->bass = strdup(tmp_chord->bass);
- }
cho_chord_free(tmp_chord);
is_chord_already_initialized = false;
// cho_debug_chord_print(songs[so]->sections[se]->lines[li]->text_above[c]->u.chord);
diff --git a/chordpro.h b/chordpro.h
@@ -253,6 +253,7 @@ void cho_songs_free(struct ChoSong **song);
int cho_line_item_count(struct ChoLineItem **items);
int cho_text_above_count(struct ChoLineItemAbove **text_above);
+char *cho_chord_name_generate(struct ChoChord *chord);
const char *cho_metadata_get(struct ChoMetadata **metadata, const char *name);
diff --git a/config.c b/config.c
@@ -67,6 +67,26 @@ static struct Note notes_latin[] = {
{ .note = "Si", .sharp = NULL, .flat = "Sib"},
};
+static struct Note notes_roman[] = {
+ { .note = "I", .sharp = "I#", .flat = NULL },
+ { .note = "II", .sharp = "II#", .flat = "IIb" },
+ { .note = "III", .sharp = NULL, .flat = "IIIb" },
+ { .note = "IV", .sharp = "IV#", .flat = NULL },
+ { .note = "V", .sharp = "V#", .flat = "Vb" },
+ { .note = "VI", .sharp = "VI#", .flat = "VIb" },
+ { .note = "VII", .sharp = NULL, .flat = "VIIb" },
+};
+
+static struct Note notes_nashville[] = {
+ { .note = "1", .sharp = "1#", .flat = NULL },
+ { .note = "2", .sharp = "2#", .flat = "2b" },
+ { .note = "3", .sharp = NULL, .flat = "3b" },
+ { .note = "4", .sharp = "4#", .flat = NULL },
+ { .note = "5", .sharp = "5#", .flat = "5b" },
+ { .note = "6", .sharp = "6#", .flat = "6b" },
+ { .note = "7", .sharp = NULL, .flat = "7b" },
+};
+
static struct PrintableItem *config_printable_item_new(const char *name)
{
struct PrintableItem *item = malloc(sizeof(struct PrintableItem));
@@ -134,6 +154,12 @@ static struct Note **config_notes_new_default(enum NamingSystem system)
case NS_LATIN:
notes = (struct Note *)¬es_latin;
break;
+ case NS_ROMAN:
+ notes = (struct Note *)¬es_roman;
+ break;
+ case NS_NASHVILLE:
+ notes = (struct Note *)¬es_nashville;
+ break;
default:
notes = (struct Note *)¬es_common;
break;
@@ -213,6 +239,25 @@ static const char *config_parse_mode_to_config_string(enum ParseMode mode)
return "strict";
}
+static enum NamingSystem config_naming_system_parse(const char *str)
+{
+ if (strcmp(str, "common") == 0 || strcmp(str, "dutch") == 0) {
+ return NS_COMMON;
+ } else if (strcmp(str, "german") == 0) {
+ return NS_GERMAN;
+ } else if (strcmp(str, "scandinavian") == 0) {
+ return NS_SCANDINAVIAN;
+ } else if (strcmp(str, "latin") == 0) {
+ return NS_LATIN;
+ } else if (strcmp(str, "roman") == 0) {
+ return NS_ROMAN;
+ } else if (strcmp(str, "nashville") == 0) {
+ return NS_NASHVILLE;
+ } else {
+ return NS_CUSTOM;
+ }
+}
+
static const char *config_naming_system_to_config_string(enum NamingSystem system)
{
switch (system) {
@@ -222,6 +267,10 @@ static const char *config_naming_system_to_config_string(enum NamingSystem syste
return "scandinavian";
case NS_LATIN:
return "latin";
+ case NS_ROMAN:
+ return "roman";
+ case NS_NASHVILLE:
+ return "nashville";
default:
return "common";
}
diff --git a/config.h b/config.h
@@ -10,7 +10,10 @@ enum NamingSystem {
NS_COMMON,
NS_GERMAN,
NS_SCANDINAVIAN,
- NS_LATIN
+ NS_LATIN,
+ NS_ROMAN,
+ NS_NASHVILLE,
+ NS_CUSTOM
};
enum ParseMode {
diff --git a/out_pdf.c b/out_pdf.c
@@ -745,7 +745,7 @@ static struct Text **text_create(struct ChoSong **songs, struct Config *config)
}
if (text_above[ch]->is_chord) {
text[t]->lines[tl]->items[tli]->style = cho_style_duplicate(text_above[ch]->u.chord->style);
- text[t]->lines[tl]->items[tli]->text = strdup(text_above[ch]->u.chord->name);
+ text[t]->lines[tl]->items[tli]->text = cho_chord_name_generate(text_above[ch]->u.chord);
} else {
text[t]->lines[tl]->items[tli]->style = cho_style_duplicate(text_above[ch]->u.annot->style);
text[t]->lines[tl]->items[tli]->text = strdup(text_above[ch]->u.annot->text);