lorid

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

commit a89f8c5ba65fd40c606e43d88a917e2a4b9d58fc
parent 5dca47ba8b780622a070cff81918121a25af75da
Author: nibo <nibo@relim.de>
Date:   Thu,  6 Mar 2025 11:21:06 +0100

Add support for {define: ... display ...}

Diffstat:
Msrc/chord_diagram.c | 120++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
Msrc/chord_diagram.h | 3++-
Msrc/chordpro.c | 121+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/chordpro.h | 5++++-
Msrc/config.c | 8++++++++
Msrc/config.h | 1+
Msrc/diagrams.h | 2++
Msrc/out_pdf.c | 10++++------
Msrc/types.h | 12++++++++++--
9 files changed, 249 insertions(+), 33 deletions(-)

diff --git a/src/chord_diagram.c b/src/chord_diagram.c @@ -302,6 +302,26 @@ draw_circle_with_char_inside( return true; } +struct ChordMap * +chord_map_new(void) +{ + struct ChordMap *map = emalloc(sizeof(struct ChordMap)); + map->name = NULL; + map->display = NULL; + return map; +} + +void +chord_map_free(struct ChordMap *map) +{ + if (!map) { + return; + } + free(map->name); + free(map->display); + free(map); +} + struct StringDiagram * string_diagram_new(void) { @@ -545,10 +565,16 @@ void chord_diagram_free(struct ChordDiagram *d) { free(d->color); - if (d->is_string_instrument) { + switch (d->type) { + case CDC_STRING: string_diagram_free(d->u.sd); - } else { + break; + case CDC_KEYBOARD: keyboard_diagram_free(d->u.kd); + break; + case CDC_CHORD_MAP: + chord_map_free(d->u.cm); + break; } free(d); } @@ -559,11 +585,17 @@ chord_diagram_copy_all_but_name(struct ChordDiagram *diagram) struct ChordDiagram *copy = emalloc(sizeof(struct ChordDiagram)); copy->show = diagram->show; copy->color = cho_color_copy(diagram->color); - copy->is_string_instrument = diagram->is_string_instrument; - if (diagram->is_string_instrument) { + copy->type = diagram->type; + switch (diagram->type) { + case CDC_STRING: copy->u.sd = string_diagram_copy_all_but_name(diagram->u.sd); - } else { + break; + case CDC_KEYBOARD: copy->u.kd = keyboard_diagram_copy_all_but_name(diagram->u.kd); + break; + default: + util_log(LOG_ERR, "Invalid ChordDiagram type '%d'", diagram->type); + return NULL; } return copy; } @@ -580,20 +612,32 @@ chord_diagram_duplicate( { int d; for (d = custom_diagrams_len-1; d >= 0; d--) { - if (custom_diagrams[d]->is_string_instrument) { + switch (custom_diagrams[d]->type) { + case CDC_STRING: if (!strcmp(custom_diagrams[d]->u.sd->name, chord_to_copy)) { - diagram->is_string_instrument = true; + diagram->type = CDC_STRING; diagram->u.sd = string_diagram_copy_all_but_name(custom_diagrams[d]->u.sd); diagram->u.sd->name = strdup(name); return CDC_STRING; } - } else { + break; + case CDC_KEYBOARD: if (!strcmp(custom_diagrams[d]->u.kd->name, chord_to_copy)) { - diagram->is_string_instrument = false; + diagram->type = CDC_KEYBOARD; diagram->u.kd = keyboard_diagram_copy_all_but_name(custom_diagrams[d]->u.kd); diagram->u.kd->name = strdup(name); return CDC_KEYBOARD; } + break; + case CDC_CHORD_MAP: + if (!strcmp(custom_diagrams[d]->u.cm->name, chord_to_copy)) { + diagram->type = CDC_CHORD_MAP; + diagram->u.cm = chord_map_new(); + diagram->u.cm->display = strdup(custom_diagrams[d]->u.cm->display); + diagram->u.cm->name = strdup(name); + return CDC_CHORD_MAP; + } + break; } } switch (instrument) { @@ -601,7 +645,7 @@ chord_diagram_duplicate( size_t i; for (i = 0; i<LENGTH(guitar_diagrams); i++) { if (!strcmp(guitar_diagrams[i].name, chord_to_copy)) { - diagram->is_string_instrument = true; + diagram->type = CDC_STRING; diagram->u.sd = string_diagram_copy_all_but_name(&guitar_diagrams[i]); diagram->u.sd->name = strdup(name); return CDC_STRING; @@ -649,7 +693,8 @@ debug_chord_diagram_print(struct ChordDiagram *diagram) printf("color: %s\n", str); - if (diagram->is_string_instrument) { + switch (diagram->type) { + case CDC_STRING: printf("name: %s\n", diagram->u.sd->name); printf("base-fret: %d\n", diagram->u.sd->base_fret); printf("frets: "); @@ -662,13 +707,19 @@ debug_chord_diagram_print(struct ChordDiagram *diagram) printf("%d ", diagram->u.sd->fingers[i]); } printf("\n"); - } else { + break; + case CDC_KEYBOARD: printf("name: %s\n", diagram->u.kd->name); printf("keys: "); for (i = 0; i<24; i++) { printf("%d ", diagram->u.kd->keys[i]); } printf("\n"); + break; + case CDC_CHORD_MAP: + printf("name: %s\n", diagram->u.cm->name); + printf("display: %s\n", diagram->u.cm->display); + break; } printf("---- CHORD DIAGRAM END ------\n"); } @@ -686,34 +737,56 @@ chord_diagrams_create( struct ChoChord **c; int d = 0; size_t i; + char **names = NULL; + char *chord_name, *parsed_chord_name, *common_chord_name; switch (config->output->diagram->instrument) { case INS_GUITAR: for (c = *chords; *c; c++) { + // cho_debug_chord_print(*c); + parsed_chord_name = (*c)->name; + common_chord_name = cho_chord_name_generate_common(*c, config); + chord_name = cho_chord_name_generate(*c); + if (!common_chord_name) { + LOG_DEBUG("cho_chord_name_generate_common failed."); + return NULL; + } for (cd = custom_diagrams; *cd; cd++) { if ( - (*cd)->is_string_instrument && + (*cd)->type == CDC_STRING && string_diagram_fret_count((*cd)->u.sd) == 6 && - !strcmp((*c)->name, (*cd)->u.sd->name) + !strcmp(parsed_chord_name, (*cd)->u.sd->name) && + !strs_has(names, chord_name) ) { + strs_add(&names, chord_name); diagrams = erealloc(diagrams, (d+1) * sizeof(struct ChordDiagram *)); diagrams[d] = chord_diagram_copy_all_but_name(*cd); - diagrams[d]->u.sd->name = cho_chord_name_generate(*c); + if (!diagrams[d]) { + LOG_DEBUG("chord_diagram_copy_all_but_name failed."); + return NULL; + } + diagrams[d]->u.sd->name = strdup(chord_name); d++; goto NEXT_CHORD; } } for (i = 0; i<LENGTH(guitar_diagrams); i++) { - if (!strcmp((*c)->name, guitar_diagrams[i].name)) { + if ( + !strcmp(common_chord_name, guitar_diagrams[i].name) && + !strs_has(names, chord_name) + ) { + strs_add(&names, chord_name); diagrams = erealloc(diagrams, (d+1) * sizeof(struct ChordDiagram *)); diagrams[d] = chord_diagram_new(); - diagrams[d]->is_string_instrument = true; + diagrams[d]->type = CDC_STRING; diagrams[d]->u.sd = string_diagram_copy_all_but_name(&guitar_diagrams[i]); - diagrams[d]->u.sd->name = cho_chord_name_generate(*c); + diagrams[d]->u.sd->name = strdup(chord_name); d++; break; } } NEXT_CHORD: ; + free(common_chord_name); + free(chord_name); } break; case INS_KEYBOARD: @@ -727,6 +800,7 @@ chord_diagrams_create( } diagrams = erealloc(diagrams, (d+1) * sizeof(struct ChordDiagram *)); diagrams[d] = NULL; + strs_free(names); return diagrams; } @@ -739,13 +813,19 @@ chord_diagram_draw( double width ) { - if (diagram->is_string_instrument) { + switch (diagram->type) { + case CDC_STRING: if (!string_diagram_draw(stream, diagram->u.sd, x, y, width)) { LOG_DEBUG("draw_string_chord_diagram failed."); return false; } - } else { + break; + case CDC_KEYBOARD: util_log(LOG_TODO, "draw_keyboard_chord_diagram()"); + break; + case CDC_CHORD_MAP: + util_log(LOG_TODO, "well"); + break; } return true; } diff --git a/src/chord_diagram.h b/src/chord_diagram.h @@ -1,5 +1,4 @@ #include <pdfio.h> -#include "types.h" enum TextRendering { FILL, @@ -18,6 +17,8 @@ void chord_diagram_free(struct ChordDiagram *d); bool chord_diagram_draw(pdfio_stream_t *stream, struct ChordDiagram *diagram, double x, double y, double width); enum ChordDiagramContent chord_diagram_duplicate(struct ChordDiagram *diagram, struct ChordDiagram **custom_diagrams, int custom_diagrams_len, const char *name, const char *chord_to_copy, enum Instrument instrument); +struct ChordMap *chord_map_new(void); +void chord_map_free(struct ChordMap *map); struct StringDiagram *string_diagram_new(void); struct KeyboardDiagram *keyboard_diagram_new(void); diff --git a/src/chordpro.c b/src/chordpro.c @@ -222,7 +222,7 @@ static const char *style_property_type_enums[] = { "SPT_COLOR" }; -static void +void cho_debug_chord_print(struct ChoChord *chord) { printf("---- BEGIN CHORD ----\n"); @@ -2223,6 +2223,7 @@ cho_chord_new(struct ChoContext *ctx) chord->qual = -1; chord->ext = NULL; chord->bass = NULL; + chord->display = NULL; return chord; } @@ -2256,6 +2257,7 @@ cho_chord_free(struct ChoChord *chord) free(chord->root); free(chord->ext); free(chord->bass); + free(chord->display); free(chord); } @@ -2270,6 +2272,7 @@ cho_chord_copy(struct ChoChord *chord) copy->root = chord->root ? strdup(chord->root) : NULL; copy->ext = chord->ext ? strdup(chord->ext) : NULL; copy->bass = chord->bass ? strdup(chord->bass) : NULL; + copy->display = chord->display ? strdup(chord->display) : NULL; return copy; } @@ -2474,6 +2477,17 @@ static struct ChoChord * cho_chord_parse(struct ChoContext *ctx, const char *str) { struct ChoChord *chord = cho_chord_new(ctx); + struct ChordDiagram *diagram; + int i; + for (i = 0; i<ctx->dia; i++) { + diagram = ctx->songs[ctx->so]->diagrams[i]; + if ( + diagram->type == CDC_CHORD_MAP && + !strcmp(str, diagram->u.cm->name) + ) { + chord->display = strdup(diagram->u.cm->display); + } + } size_t str_len = strlen(str); size_t bytes_parsed = 0; int ret; @@ -2504,8 +2518,78 @@ cho_chord_parse(struct ChoContext *ctx, const char *str) } char * +cho_chord_name_generate_common(struct ChoChord *chord, struct Config *config) +{ + struct Note **notes = config->output->notes; + struct Note *notes_common; + char *root = NULL; + int i; + if (chord->is_canonical) { + notes_common = config_notes_common(); + for (i = 0; i<7; i++) { + if (!strcmp(notes[i]->note, chord->root)) { + root = notes_common[i].note; + break; + } + if (notes[i]->sharp && !strcmp(notes[i]->sharp, chord->root)) { + root = notes_common[i].sharp; + break; + } + if (notes[i]->flat && !strcmp(notes[i]->flat, chord->root)) { + root = notes_common[i].flat; + break; + } + } + free(notes_common); + int n = 0; + char *name = NULL; + size_t name_len = 0; + name_len += strlen(root); + name = erealloc(name, name_len * sizeof(char)); + for (i = 0; root[i]; i++) { + name[n] = root[i]; + n++; + } + const char *qual = chord_qualifiers[chord->qual]; + name_len += strlen(qual); + name = erealloc(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 = erealloc(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 = erealloc(name, name_len * sizeof(char)); + name[n] = '/'; + n++; + for (i = 0; chord->bass[i]; i++) { + name[n] = chord->bass[i]; + n++; + } + } + name_len++; + name = erealloc(name, name_len * sizeof(char)); + name[n] = 0; + return name; + } + return strdup(chord->name); +} + +char * cho_chord_name_generate(struct ChoChord *chord) { + if (chord->display) { + return strdup(chord->display); + } if (chord->is_canonical) { int n = 0; int i; @@ -3216,6 +3300,7 @@ cho_chord_diagram_parse( char base_fret[3]; char diagram_value[7+1]; char chord_to_copy[20]; + char display[20]; int i = 0; int f = 0; int fret_count = 0; @@ -3272,6 +3357,10 @@ cho_chord_diagram_parse( } else if (!strcmp(option, "copy")) { state = CDS_COPY; + } else + if (!strcmp(option, "display")) { + state = CDS_DISPLAY; + future_content = CDC_CHORD_MAP; } else { cho_log(ctx, LOG_ERR, "Invalid option '%s' in define directive.", option); return NULL; @@ -3282,15 +3371,20 @@ cho_chord_diagram_parse( current_content = future_content; switch (future_content) { case CDC_STRING: - diagram->is_string_instrument = true; + diagram->type = CDC_STRING; diagram->u.sd = string_diagram_new(); diagram->u.sd->name = strdup(name); break; case CDC_KEYBOARD: - diagram->is_string_instrument = false; + diagram->type = CDC_KEYBOARD; diagram->u.kd = keyboard_diagram_new(); diagram->u.kd->name = strdup(name); break; + case CDC_CHORD_MAP: + diagram->type = CDC_CHORD_MAP; + diagram->u.cm = chord_map_new(); + diagram->u.cm->name = strdup(name); + break; default: cho_log(ctx, LOG_ERR, "'future_content' cannot be empty at this point.\n"); } @@ -3492,6 +3586,17 @@ cho_chord_diagram_parse( i++; break; } + case CDS_DISPLAY: { + if (is_whitespace(*c)) { + display[i] = 0; + i = 0; + diagram->u.cm->display = strdup(display); + break; + } + display[i] = *c; + i++; + break; + } } } switch (state) { @@ -3565,6 +3670,11 @@ cho_chord_diagram_parse( } break; } + case CDS_DISPLAY: { + display[i] = 0; + diagram->u.cm->display = strdup(display); + break; + } default: } if ( @@ -3576,6 +3686,10 @@ cho_chord_diagram_parse( cho_log(ctx, LOG_ERR, "The number of frets (%d) and fingers (%d) in the chord diagram must be equal.", fret_count, finger_count); return NULL; } + if (current_content == -1) { + cho_log(ctx, LOG_ERR, "The chord diagram is invalid."); + return NULL; + } return diagram; } @@ -5204,6 +5318,7 @@ cho_songs_parse(const char *str, const char *chordpro_filepath, struct Config *c LOG_DEBUG("cho_chord_diagram_parse failed."); return NULL; } + // debug_chord_diagram_print(diagram); ctx.songs[ctx.so]->diagrams = erealloc(ctx.songs[ctx.so]->diagrams, (ctx.dia+1) * sizeof(struct ChordDiagram *)); ctx.songs[ctx.so]->diagrams[ctx.dia] = diagram; ctx.dia++; diff --git a/src/chordpro.h b/src/chordpro.h @@ -27,7 +27,8 @@ enum ChordDiagramState { CDS_FINGERS, CDS_KEYS, CDS_DIAGRAM, - CDS_COPY + CDS_COPY, + CDS_DISPLAY }; enum MetadataSubstitutionState { @@ -190,6 +191,7 @@ void cho_songs_free(struct ChoSong **song); int cho_line_item_count(struct ChoLineItem **items); char *cho_chord_name_generate(struct ChoChord *chord); +char *cho_chord_name_generate_common(struct ChoChord *chord, struct Config *config); void cho_chords_add(struct ChoChord ***chords, struct ChoChord *chord); bool cho_chords_has(struct ChoChord **chords, struct ChoChord *chord); @@ -223,6 +225,7 @@ const char *cho_font_style_to_config_string(enum FontStyle style); enum FontWeight cho_font_weight_parse(const char *str); const char *cho_font_weight_to_config_string(enum FontWeight weight); +void cho_debug_chord_print(struct ChoChord *chord); void cho_debug_style_print(struct ChoStyle *style); // void cho_debug_songs_print(struct ChoSong **songs); diff --git a/src/config.c b/src/config.c @@ -259,6 +259,14 @@ config_notes_free(struct Note **notes) free(notes); } +struct Note * +config_notes_common(void) +{ + struct Note *notes = emalloc(sizeof(notes_common)); + memcpy(notes, notes_common, sizeof(notes_common)); + return notes; +} + static struct Note ** config_notes_new_default(enum NotationSystem system) { diff --git a/src/config.h b/src/config.h @@ -13,6 +13,7 @@ struct Config *config_load(const char *filepath); void config_free(struct Config *config); void config_print_default(void); +struct Note *config_notes_common(void); struct InstrumentInfo config_instrument_get(enum Instrument ins); #endif /* _CONFIG_H_ */ diff --git a/src/diagrams.h b/src/diagrams.h @@ -1,3 +1,5 @@ +/* INFO: All the diagrams' name are in the notation system NS_COMMON */ + static struct StringDiagram guitar_diagrams[] = { { .name = "C", diff --git a/src/out_pdf.c b/src/out_pdf.c @@ -2273,7 +2273,7 @@ pdf_content_create( struct PDFText ***texts; struct PDFImage ***imgs; struct PDFContext ctx; - struct ChordDiagram ***diagrams, **dgrams, **dgrams_begin; + struct ChordDiagram ***diagrams, **dgrams, **d; bool show_diagram = config->output->diagram->show; bool start_song_on_new_page = config->output->start_song_on_new_page; double width, height; @@ -2305,14 +2305,12 @@ pdf_content_create( if (chords) { qsort(chords, cho_chord_count(chords), sizeof(struct ChoChord *), cho_chord_compare); dgrams = chord_diagrams_create(config, &chords, songs[s]->diagrams); - dgrams_begin = dgrams; - while (*dgrams) { + for (d = dgrams; *d; d++) { *diagrams = erealloc(*diagrams, (ctx.diagram+1) * sizeof(struct ChordDiagram *)); - (*diagrams)[ctx.diagram] = *dgrams; + (*diagrams)[ctx.diagram] = *d; ctx.diagram++; - dgrams++; } - free(dgrams_begin); + free(dgrams); } cho_chords_free(chords); } diff --git a/src/types.h b/src/types.h @@ -47,7 +47,8 @@ enum BreakType : int8_t { enum ChordDiagramContent : int8_t { CDC_STRING, - CDC_KEYBOARD + CDC_KEYBOARD, + CDC_CHORD_MAP }; enum ChordQualifier { @@ -166,6 +167,7 @@ struct ChoChord { enum ChordQualifier qual; char *ext; char *bass; + char *display; }; struct ChoText { @@ -254,13 +256,19 @@ struct KeyboardDiagram { int8_t keys[24]; }; +struct ChordMap { + char *name; + char *display; +}; + struct ChordDiagram { bool show; struct RGBColor *color; - bool is_string_instrument; + enum ChordDiagramContent type; union { struct StringDiagram *sd; struct KeyboardDiagram *kd; + struct ChordMap *cm; } u; };