lorid

convert chordpro to pdf
git clone git://git.relim.de/lorid.git
Log | Files | Refs | README | LICENSE

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:
Mchordpro.c | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
Mchordpro.h | 1+
Mconfig.c | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Mconfig.h | 5++++-
Mout_pdf.c | 2+-
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 *)&notes_latin; break; + case NS_ROMAN: + notes = (struct Note *)&notes_roman; + break; + case NS_NASHVILLE: + notes = (struct Note *)&notes_nashville; + break; default: notes = (struct Note *)&notes_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);