commit a89f8c5ba65fd40c606e43d88a917e2a4b9d58fc
parent 5dca47ba8b780622a070cff81918121a25af75da
Author: nibo <nibo@relim.de>
Date: Thu, 6 Mar 2025 11:21:06 +0100
Add support for {define: ... display ...}
Diffstat:
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;
};