lorid

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

commit 98628363cde64aef5ce5c14b4a3f92cdf0a5ccc5
parent b9bdabaf1aeb7a59dcabfc617b8db5b42e1cdb79
Author: nibo <nibo@relim.de>
Date:   Sat,  8 Feb 2025 17:35:23 +0100

Add copy option in 'define' directive

Diffstat:
Mchord_diagram.c | 114+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Mchord_diagram.h | 1+
Mchordpro.c | 149++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
Mchordpro.h | 8++------
Mout_pdf.c | 11+++++++----
Mtypes.h | 5+++++
6 files changed, 199 insertions(+), 89 deletions(-)

diff --git a/chord_diagram.c b/chord_diagram.c @@ -320,22 +320,6 @@ string_diagram_free(struct StringDiagram *d) free(d); } -/* static struct StringDiagram * -string_diagram_copy(struct StringDiagram *diagram) -{ - struct StringDiagram *copy = emalloc(sizeof(struct StringDiagram)); - copy->name = strdup(diagram->name); - copy->base_fret = diagram->base_fret; - int i; - for (i = 0; i<12; i++) { - copy->frets[i] = diagram->frets[i]; - } - for (i = 0; i<12; i++) { - copy->fingers[i] = diagram->fingers[i]; - } - return copy; -} */ - static struct StringDiagram * string_diagram_copy_all_but_name(struct StringDiagram *diagram) { @@ -522,6 +506,14 @@ keyboard_diagram_new(void) return d; } +static struct KeyboardDiagram * +keyboard_diagram_copy_all_but_name(struct KeyboardDiagram *diagram) +{ + struct KeyboardDiagram *copy = keyboard_diagram_new(); + memcpy(copy->keys, diagram->keys, 24); + return copy; +} + static void keyboard_diagram_free(struct KeyboardDiagram *d) { @@ -529,18 +521,6 @@ keyboard_diagram_free(struct KeyboardDiagram *d) free(d); } -/* static struct KeyboardDiagram * -keyboard_diagram_copy(struct KeyboardDiagram *diagram) -{ - struct KeyboardDiagram *copy = emalloc(sizeof(struct KeyboardDiagram)); - copy->name = strdup(diagram->name); - int i; - for (i = 0; i<24; i++) { - copy->keys[i] = diagram->keys[i]; - } - return copy; -} */ - struct ChordDiagram * chord_diagram_new() { @@ -562,19 +542,74 @@ chord_diagram_free(struct ChordDiagram *d) free(d); } -/* static struct ChordDiagram * -chord_diagram_copy(struct ChordDiagram *diagram) +static struct ChordDiagram * +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->is_string_instrument = true; - copy->u.sd = string_diagram_copy(diagram->u.sd); + copy->u.sd = string_diagram_copy_all_but_name(diagram->u.sd); } else { - copy->is_string_instrument = false; - copy->u.kd = keyboard_diagram_copy(diagram->u.kd); + copy->u.kd = keyboard_diagram_copy_all_but_name(diagram->u.kd); } return copy; -} */ +} + +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 +) +{ + int d; + for (d = custom_diagrams_len-1; d >= 0; d--) { + if (custom_diagrams[d]->is_string_instrument) { + if (!strcmp(custom_diagrams[d]->u.sd->name, chord_to_copy)) { + diagram->is_string_instrument = true; + diagram->u.sd = string_diagram_copy_all_but_name(custom_diagrams[d]->u.sd); + diagram->u.sd->name = strdup(name); + return CDC_STRING; + } + } else { + if (!strcmp(custom_diagrams[d]->u.kd->name, chord_to_copy)) { + diagram->is_string_instrument = false; + diagram->u.kd = keyboard_diagram_copy_all_but_name(custom_diagrams[d]->u.kd); + diagram->u.kd->name = strdup(name); + return CDC_KEYBOARD; + } + } + } + switch (instrument) { + case INS_GUITAR: { + 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->u.sd = string_diagram_copy_all_but_name(&guitar_diagrams[i]); + diagram->u.sd->name = strdup(name); + return CDC_STRING; + } + } + break; + } + case INS_KEYBOARD: { + break; + } + case INS_MANDOLIN: { + break; + } + case INS_UKULELE: { + break; + } + } + return -1; +} void chord_diagrams_free(struct ChordDiagram **diagrams) @@ -650,11 +685,9 @@ chord_diagrams_create( !strcmp((*c)->name, (*cd)->u.sd->name) ) { diagrams = erealloc(diagrams, (d+1) * sizeof(struct ChordDiagram *)); - // diagrams[d] = chord_diagram_copy(*cd); - diagrams[d] = emalloc(sizeof(struct ChordDiagram)); - diagrams[d]->is_string_instrument = true; - diagrams[d]->u.sd = string_diagram_copy_all_but_name((*cd)->u.sd); + diagrams[d] = chord_diagram_copy_all_but_name(*cd); diagrams[d]->u.sd->name = cho_chord_name_generate(*c); + printf("custom: name '%s'\n", diagrams[d]->u.sd->name); d++; goto NEXT_CHORD; } @@ -662,10 +695,11 @@ chord_diagrams_create( for (i = 0; i<LENGTH(guitar_diagrams); i++) { if (!strcmp((*c)->name, guitar_diagrams[i].name)) { diagrams = erealloc(diagrams, (d+1) * sizeof(struct ChordDiagram *)); - diagrams[d] = emalloc(sizeof(struct ChordDiagram)); + diagrams[d] = chord_diagram_new(); diagrams[d]->is_string_instrument = true; diagrams[d]->u.sd = string_diagram_copy_all_but_name(&guitar_diagrams[i]); diagrams[d]->u.sd->name = cho_chord_name_generate(*c); + printf("predefined: name '%s'\n", diagrams[d]->u.sd->name); d++; } } diff --git a/chord_diagram.h b/chord_diagram.h @@ -15,6 +15,7 @@ enum Direction { struct ChordDiagram *chord_diagram_new(); 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 StringDiagram *string_diagram_new(void); struct KeyboardDiagram *keyboard_diagram_new(void); diff --git a/chordpro.c b/chordpro.c @@ -19,6 +19,7 @@ static const char *font_styles[] = { "normal", "oblique", "italic" }; static const char *font_weights[] = { "normal", "bold" }; static const char *line_styles[] = { "single", "double", "none" }; static const char *chord_qualifiers[] = { "m", "", "+", "°" }; +static const char *instruments[] = { "guitar", "keyboard", "mandolin", "ukulele" }; static const char *state_enums[] = { "STATE_LYRICS", @@ -2765,7 +2766,11 @@ finger_to_int(char c) } static struct ChordDiagram * -cho_chord_diagram_parse(const char *str) +cho_chord_diagram_parse( + const char *str, + struct ChordDiagram **custom_diagrams, + int custom_diagrams_len +) { struct ChordDiagram *diagram = chord_diagram_new(); enum ChordDiagramState state = CDS_NAME; @@ -2777,11 +2782,8 @@ cho_chord_diagram_parse(const char *str) char key[3]; char base_fret[3]; char diagram_value[7+1]; - int n = 0; - int o = 0; - int k = 0; - int b = 0; - int d = 0; + char chord_to_copy[20]; + int i = 0; int f = 0; int fret_count = 0; int finger_count = 0; @@ -2793,27 +2795,28 @@ cho_chord_diagram_parse(const char *str) switch (state) { case CDS_NAME: { if (is_whitespace(*c)) { - if (n == 0) { + if (i == 0) { break; } - name[n] = 0; + name[i] = 0; + i = 0; state = CDS_OPTION_NAME; break; } - if (n > 18) { + if (i > 18) { cho_log(LOG_ERR, "Chord name in chord diagram is too long."); return NULL; } - name[n] = *c; - n++; + name[i] = *c; + i++; break; } case CDS_OPTION_NAME: { if (is_whitespace(*c)) { - if (o == 0) { + if (i == 0) { break; } - option[o] = 0; + option[i] = 0; future_content = -1; if (!strcmp(option, "base-fret")) { state = CDS_BASE_FRET; @@ -2833,12 +2836,15 @@ cho_chord_diagram_parse(const char *str) } else if (!strcmp(option, "diagram")) { state = CDS_DIAGRAM; + } else + if (!strcmp(option, "copy")) { + state = CDS_COPY; } else { cho_log(LOG_ERR, "Invalid option '%s' in define directive.", option); return NULL; } - memset(option, 0, o); - o = 0; + memset(option, 0, i); + i = 0; if (current_content == -1 && future_content != -1) { current_content = future_content; switch (future_content) { @@ -2858,20 +2864,21 @@ cho_chord_diagram_parse(const char *str) } break; } - if (o > 8) { + if (i > 8) { cho_log(LOG_ERR, "Option in chord diagram is too long."); return NULL; } - option[o] = *c; - o++; + option[i] = *c; + i++; break; } case CDS_BASE_FRET: { if (is_whitespace(*c)) { - if (b == 0) { + if (i == 0) { break; } - base_fret[b] = 0; + base_fret[i] = 0; + i = 0; l = str_to_number(base_fret); if (l == -1) { LOG_DEBUG("str_to_number failed."); @@ -2882,17 +2889,19 @@ cho_chord_diagram_parse(const char *str) cho_log(LOG_ERR, "Invalid base-fret value '%c' in chord diagram.", *c); return NULL; } + printf("base-fret %d\n", (int8_t)l); diagram->u.sd->base_fret = (int8_t)l; state = CDS_OPTION_NAME; break; } - if (b > 1) { + if (i > 1) { cho_log(LOG_ERR, "base-fret value is too long."); printf("c: %c\n", *c); return NULL; } - base_fret[b] = *c; - b++; + printf("parsing base-fret '%c'\n", *c); + base_fret[i] = *c; + i++; break; } case CDS_FRETS: { @@ -2965,11 +2974,11 @@ cho_chord_diagram_parse(const char *str) } case CDS_KEYS: { if (is_whitespace(*c)) { - if (k == 0) { + if (i == 0) { break; } - key[k] = 0; - k = 0; + key[i] = 0; + i = 0; l = str_to_number(key); if (l == -1) { LOG_DEBUG("str_to_number failed."); @@ -2989,22 +2998,22 @@ cho_chord_diagram_parse(const char *str) c--; break; } - if (k > 1) { - cho_log(LOG_ERR, "Too high key value in chord diagram. '%d'", k); + if (i > 1) { + cho_log(LOG_ERR, "Too high key value in chord diagram. '%d'", i); printf("key '%s'\n", key); return NULL; } - key[k] = *c; - k++; + key[i] = *c; + i++; break; } case CDS_DIAGRAM: { if (is_whitespace(*c)) { - if (d == 0) { + if (i == 0) { break; } - diagram_value[d] = 0; - d = 0; + diagram_value[i] = 0; + i = 0; if (!strcmp(diagram_value, "off")) { diagram->show = false; } else @@ -3021,15 +3030,58 @@ cho_chord_diagram_parse(const char *str) state = CDS_OPTION_NAME; break; } - diagram_value[d] = *c; - d++; + diagram_value[i] = *c; + i++; + break; + } + case CDS_COPY: { + if (is_whitespace(*c)) { + if (i == 0) { + break; + } + chord_to_copy[i] = 0; + if (current_content != -1) { + cho_log(LOG_ERR, "The define options 'base-fret', 'frets', 'fingers' and 'keys' are not allowed before the 'copy' option."); + return NULL; + } + enum Instrument ins = g_config->output->diagram->instrument; + current_content = chord_diagram_duplicate(diagram, custom_diagrams, custom_diagrams_len, name, chord_to_copy, ins); + if (current_content == -1) { + cho_log(LOG_ERR, "Can't copy the diagram for the chord '%s'" + "because no previous definition was found and also" + "no predefined chord diagram for the instrument '%s'" + "was found.", chord_to_copy, instruments[ins]); + return NULL; + } + i = 0; + state = CDS_OPTION_NAME; + break; + } + chord_to_copy[i] = *c; + i++; break; } } } switch (state) { + case CDS_BASE_FRET: { + base_fret[i] = 0; + i = 0; + l = str_to_number(base_fret); + if (l == -1) { + LOG_DEBUG("str_to_number failed."); + cho_log(LOG_ERR, "Invalid base-fret value '%s' in chord diagram.", base_fret); + return NULL; + } + if (l == 0) { + cho_log(LOG_ERR, "Invalid base-fret value '%c' in chord diagram.", *c); + return NULL; + } + diagram->u.sd->base_fret = (int8_t)l; + break; + } case CDS_KEYS: { - key[k] = 0; + key[i] = 0; if (strlen(key) > 0) { l = str_to_number(key); if (l == -1) { @@ -3046,7 +3098,7 @@ cho_chord_diagram_parse(const char *str) break; } case CDS_DIAGRAM: { - diagram_value[d] = 0; + diagram_value[i] = 0; if (!strcmp(diagram_value, "off")) { diagram->show = false; } else @@ -3062,8 +3114,27 @@ cho_chord_diagram_parse(const char *str) } } break; - default: } + case CDS_COPY: { + chord_to_copy[i] = 0; + if (current_content != -1) { + cho_log(LOG_ERR, "The define options 'base-fret', 'frets'," + "'fingers' and 'keys' are not allowed before the 'copy'" + "option."); + return NULL; + } + enum Instrument ins = g_config->output->diagram->instrument; + current_content = chord_diagram_duplicate(diagram, custom_diagrams, custom_diagrams_len, name, chord_to_copy, ins); + if (current_content == -1) { + cho_log(LOG_ERR, "Can't copy the diagram for the chord '%s' because" + "no previous definition was found and also no predefined" + "chord diagram for the instrument '%s' was found.", + chord_to_copy, instruments[ins]); + return NULL; + } + break; + } + default: } if ( current_content == CDC_STRING && @@ -4648,7 +4719,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) th++; break; case DEFINE: - diagram = cho_chord_diagram_parse(directive_value); + diagram = cho_chord_diagram_parse(directive_value, songs[so]->diagrams, dia); if (!diagram) { LOG_DEBUG("cho_chord_diagram_parse failed."); return NULL; diff --git a/chordpro.h b/chordpro.h @@ -19,11 +19,6 @@ enum AttrValueSyntax : int8_t { AVS_UNQUOTED }; -enum ChordDiagramContent : int8_t { - CDC_STRING, - CDC_KEYBOARD -}; - enum ChordDiagramState { CDS_NAME, CDS_OPTION_NAME, @@ -31,7 +26,8 @@ enum ChordDiagramState { CDS_FRETS, CDS_FINGERS, CDS_KEYS, - CDS_DIAGRAM + CDS_DIAGRAM, + CDS_COPY }; enum ChordDirective { diff --git a/out_pdf.c b/out_pdf.c @@ -2709,11 +2709,14 @@ pdf_content_render(struct PDFContent *content, pdfio_file_t *file) struct ChordDiagram **d; /* TODO: Handle line break when too long */ for (d = pages[p]->diagrams; *d; d++) { - if (!chord_diagram_draw(stream, *d, x, y, size)) { - LOG_DEBUG("chord_diagram_draw failed."); - return false; + debug_chord_diagram_print(*d); + if ((*d)->show) { + if (!chord_diagram_draw(stream, *d, x, y, size)) { + LOG_DEBUG("chord_diagram_draw failed."); + return false; + } + x += size + padding; } - x += size + padding; } } if (!pdfioStreamClose(stream)) { diff --git a/types.h b/types.h @@ -42,6 +42,11 @@ enum BreakType : int8_t { BT_COLUMN }; +enum ChordDiagramContent : int8_t { + CDC_STRING, + CDC_KEYBOARD +}; + enum ChordQualifier { CQ_MIN, CQ_MAJ,