chord_diagram.c (20905B)
1 #include <string.h> 2 #include <ctype.h> 3 #include <pdfio.h> 4 #include <pdfio-content.h> 5 #include "core.h" 6 #include "out_pdf.h" 7 #include "config.h" 8 #include "chordpro.h" 9 #include "chord_diagram.h" 10 #include "diagrams.h" 11 12 static bool 13 text_show( 14 pdfio_stream_t *stream, 15 bool unicode, 16 const char *text, 17 double x, 18 double y 19 ) 20 { 21 if (!pdfioContentSetTextRenderingMode(stream, PDFIO_TEXTRENDERING_FILL)) { 22 fprintf(stderr, "pdfioContentSetTextRenderingMode failed.\n"); 23 return false; 24 } 25 if (!pdfioContentTextBegin(stream)) { 26 fprintf(stderr, "pdfioContentTextBegin failed.\n"); 27 return false; 28 } 29 if (!pdfioContentTextMoveTo(stream, x, y)) { 30 fprintf(stderr, "pdfioContentTextMoveTo failed.\n"); 31 return false; 32 } 33 if (!pdfioContentTextShow(stream, unicode, text)) { 34 fprintf(stderr, "pdfioContentTextShow failed.\n"); 35 return false; 36 } 37 if (!pdfioContentTextEnd(stream)) { 38 fprintf(stderr, "pdfioContentTextEnd failed.\n"); 39 return false; 40 } 41 return true; 42 } 43 44 static bool 45 draw_rectangle( 46 pdfio_stream_t *stream, 47 double x, 48 double y, 49 double width, 50 double height, 51 enum TextRendering type 52 ) 53 { 54 if (!pdfioContentSetFillColorRGB(stream, 0.0, 0.0, 0.0)) { 55 fprintf(stderr, "pdfioContentSetFillColorRGB failed.\n"); 56 return false; 57 } 58 if (!pdfioContentSetStrokeColorRGB(stream, 0.0, 0.0, 0.0)) { 59 fprintf(stderr, "pdfioContentSetStrokeColorRGB failed.\n"); 60 return false; 61 } 62 if (!pdfioContentPathRect(stream, x, y, width, height)) { 63 fprintf(stderr, "pdfioContentPathRect failed.\n"); 64 return false; 65 } 66 switch (type) { 67 case FILL_AND_STROKE: 68 if (!pdfioContentFillAndStroke(stream, true)) { 69 fprintf(stderr, "pdfioContentFillAndStroke failed.\n"); 70 return false; 71 } 72 break; 73 case FILL: 74 if (!pdfioContentFill(stream, true)) { 75 fprintf(stderr, "pdfioContentFill failed.\n"); 76 return false; 77 } 78 break; 79 case STROKE: 80 if (!pdfioContentStroke(stream)) { 81 fprintf(stderr, "pdfioContentStroke failed.\n"); 82 return false; 83 } 84 break; 85 } 86 return true; 87 } 88 89 static bool 90 draw_line( 91 pdfio_stream_t *stream, 92 double x, 93 double y, 94 double width, 95 enum Direction direction 96 ) 97 { 98 if (!pdfioContentPathMoveTo(stream, x, y)) { 99 fprintf(stderr, "pdfioContentPathMoveTo failed.\n"); 100 return false; 101 } 102 if (direction == HORIZONTAL) { 103 if (!pdfioContentPathLineTo(stream, x+width, y)) { 104 fprintf(stderr, "pdfioContentPathLineTo failed.\n"); 105 return false; 106 } 107 } else { 108 if (!pdfioContentPathLineTo(stream, x, y+width)) { 109 fprintf(stderr, "pdfioContentPathLineTo failed.\n"); 110 return false; 111 } 112 } 113 if (!pdfioContentSetStrokeColorRGB(stream, 0.0, 0.0, 0.0)) { 114 fprintf(stderr, "pdfioContentSetStrokeColorRGB failed.\n"); 115 return false; 116 } 117 if (!pdfioContentStroke(stream)) { 118 fprintf(stderr, "pdfioContentFill failed.\n"); 119 return false; 120 } 121 return true; 122 } 123 124 static bool 125 draw_bezier_oval_quarter( 126 pdfio_stream_t *stream, 127 double center_x, 128 double center_y, 129 double size_x, 130 double size_y 131 ) 132 { 133 if (!pdfioContentPathMoveTo(stream, center_x - size_x, center_y)) { 134 fprintf(stderr, "pdfioContentPathMoveTo failed.\n"); 135 return false; 136 } 137 if (!pdfioContentPathCurve( 138 stream, 139 center_x - size_x, 140 center_y - 0.552 * size_y, 141 center_x - 0.552 * size_x, 142 center_y - size_y, 143 center_x, 144 center_y - size_y 145 )) { 146 fprintf(stderr, "pdfioContentPathCurve failed.\n"); 147 return false; 148 } 149 return true; 150 } 151 152 static bool 153 draw_bezier_oval( 154 pdfio_stream_t *stream, 155 double center_x, 156 double center_y, 157 double size_x, 158 double size_y 159 ) 160 { 161 if (!pdfioContentSetStrokeColorRGB(stream, 0.0, 0.0, 0.0)) { 162 fprintf(stderr, "pdfioContentSetStrokeColorRGB failed.\n"); 163 return false; 164 } 165 if (!draw_bezier_oval_quarter(stream, center_x, center_y, -size_x, size_y)) { 166 fprintf(stderr, "draw_bezier_oval_quarter failed."); 167 return false; 168 } 169 if (!draw_bezier_oval_quarter(stream, center_x, center_y, size_x, size_y)) { 170 fprintf(stderr, "draw_bezier_oval_quarter failed."); 171 return false; 172 } 173 if (!draw_bezier_oval_quarter(stream, center_x, center_y, size_x, -size_y)) { 174 fprintf(stderr, "draw_bezier_oval_quarter failed."); 175 return false; 176 } 177 if (!draw_bezier_oval_quarter(stream, center_x, center_y, -size_x, -size_y)) { 178 fprintf(stderr, "draw_bezier_oval_quarter failed."); 179 return false; 180 } 181 if (!pdfioContentStroke(stream)) { 182 fprintf(stderr, "pdfioContentStroke failed.\n"); 183 return false; 184 } 185 return true; 186 } 187 188 static bool 189 draw_bezier_circle( 190 pdfio_stream_t *stream, 191 double center_x, 192 double center_y, 193 double size 194 ) 195 { 196 if (!pdfioContentSetLineWidth(stream, size * 0.4)) { 197 fprintf(stderr, "pdfioContentSetLineWidth failed.\n"); 198 return false; 199 } 200 if (!draw_bezier_oval(stream, center_x, center_y, size, size)) { 201 fprintf(stderr, "draw_bezier_oval failed."); 202 return false; 203 } 204 return true; 205 } 206 207 static bool 208 draw_x(pdfio_stream_t *stream, double x, double y, double size) 209 { 210 if (!pdfioContentSetLineWidth(stream, size * 0.4)) { 211 fprintf(stderr, "pdfioContentSetLineWidth failed.\n"); 212 return false; 213 } 214 if (!pdfioContentSetStrokeColorRGB(stream, 0.0, 0.0, 0.0)) { 215 fprintf(stderr, "pdfioContentSetStrokeColorRGB failed.\n"); 216 return false; 217 } 218 if (!pdfioContentPathMoveTo(stream, x - size, y - size)) { 219 fprintf(stderr, "pdfioContentPathMoveTo failed.\n"); 220 return false; 221 } 222 if (!pdfioContentPathLineTo(stream, x + size, y + size)) { 223 fprintf(stderr, "pdfioContentPathLineTo failed.\n"); 224 return false; 225 } 226 if (!pdfioContentStroke(stream)) { 227 fprintf(stderr, "pdfioContentFill failed.\n"); 228 return false; 229 } 230 if (!pdfioContentPathMoveTo(stream, x - size, y + size)) { 231 fprintf(stderr, "pdfioContentPathMoveTo failed.\n"); 232 return false; 233 } 234 if (!pdfioContentPathLineTo(stream, x + size, y - size)) { 235 fprintf(stderr, "pdfioContentPathLineTo failed.\n"); 236 return false; 237 } 238 if (!pdfioContentStroke(stream)) { 239 fprintf(stderr, "pdfioContentFill failed.\n"); 240 return false; 241 } 242 return true; 243 } 244 245 static bool 246 is_valid_circle_char(char c) 247 { 248 if (c >= '/' && c <= '9') { 249 return true; 250 } 251 if (c >= 'A' && c <= 'Z') { 252 return true; 253 } 254 return false; 255 } 256 257 static bool 258 draw_circle_with_char_inside( 259 pdfio_stream_t *stream, 260 double x, 261 double y, 262 double field_width, 263 char c 264 ) 265 { 266 if (!is_valid_circle_char(c)) { 267 fprintf(stderr, "is_valid_circle_char failed.\n"); 268 return false; 269 } 270 char str[2]; 271 str[0] = c; 272 str[1] = 0; 273 if (!pdfioContentSetTextFont(stream, "chord-diagram-symbols", field_width)) { 274 fprintf(stderr, "pdfioContentSetTextFont failed.\n"); 275 return false; 276 } 277 /* INFO: Needs to be the color of the page background. This cannot be set at the moment. It will always be white. */ 278 if (!pdfioContentSetFillColorRGB(stream, 1.0, 1.0, 1.0)) { 279 fprintf(stderr, "pdfioContentSetFillColorRGB failed.\n"); 280 return false; 281 } 282 if (!text_show(stream, true, "/", x-field_width/2, y-field_width/2.8)) { 283 fprintf(stderr, "text_show failed."); 284 return false; 285 } 286 if (!pdfioContentSetFillColorRGB(stream, 0.0, 0.0, 0.0)) { 287 fprintf(stderr, "pdfioContentSetFillColorRGB failed.\n"); 288 return false; 289 } 290 if (!text_show(stream, true, (char *)&str, x-field_width/2, y-field_width/2.8)) { 291 fprintf(stderr, "text_show failed."); 292 return false; 293 } 294 return true; 295 } 296 297 struct ChordMap * 298 chord_map_new(void) 299 { 300 struct ChordMap *map = emalloc(sizeof(struct ChordMap)); 301 map->name = NULL; 302 map->display = NULL; 303 return map; 304 } 305 306 void 307 chord_map_free(struct ChordMap *map) 308 { 309 if (!map) { 310 return; 311 } 312 free(map->name); 313 free(map->display); 314 free(map); 315 } 316 317 struct StringDiagram * 318 string_diagram_new(void) 319 { 320 struct StringDiagram *d = emalloc(sizeof(struct StringDiagram)); 321 d->name = NULL; 322 d->base_fret = -2; 323 memset(d->frets, -2, sizeof(d->frets)); 324 memset(d->fingers, -2, sizeof(d->fingers)); 325 return d; 326 } 327 328 static int 329 string_diagram_string_count(struct StringDiagram *d) 330 { 331 int i; 332 for (i = 0; d->frets[i] != -2 && i < 12; i++); 333 return i; 334 } 335 336 static void 337 string_diagram_free(struct StringDiagram *d) 338 { 339 if (!d) { 340 return; 341 } 342 free(d->name); 343 free(d); 344 } 345 346 static struct StringDiagram * 347 string_diagram_copy_all_but_name(struct StringDiagram *diagram) 348 { 349 struct StringDiagram *copy = emalloc(sizeof(struct StringDiagram)); 350 copy->base_fret = diagram->base_fret; 351 int i; 352 for (i = 0; i<MAX_STRINGS; i++) { 353 copy->frets[i] = diagram->frets[i]; 354 } 355 for (i = 0; i<MAX_STRINGS; i++) { 356 copy->fingers[i] = diagram->fingers[i]; 357 } 358 return copy; 359 } 360 361 /* static bool 362 string_diagram_is_valid(struct StringDiagram *d) 363 { 364 int i; 365 size_t fret_count, finger_count; 366 if (d->base_fret < 1 || d->base_fret > 99) { 367 return false; 368 } 369 i = 0; 370 while (d->frets[i] != -2 && i < 12) { 371 i++; 372 } 373 fret_count = i; 374 i = 0; 375 while (d->fingers[i] != -2 && i < 12) { 376 i++; 377 } 378 finger_count = i; 379 if (finger_count > 0 && fret_count != finger_count) { 380 return false; 381 } 382 return true; 383 } */ 384 385 static size_t 386 string_diagram_fret_count(struct StringDiagram *d) 387 { 388 int i; 389 for (i = 0; d->frets[i] != -2 && i < MAX_STRINGS; i++); 390 return i; 391 } 392 393 static char 394 finger_to_char(int8_t finger) 395 { 396 switch (finger) { 397 case 1: 398 return '1'; 399 case 2: 400 return '2'; 401 case 3: 402 return '3'; 403 case 4: 404 return '4'; 405 default: 406 return '/'; 407 } 408 } 409 410 static bool 411 string_diagram_draw( 412 struct PDFContext *ctx, 413 pdfio_stream_t *stream, 414 struct StringDiagram *diagram, 415 double x, 416 double y, 417 double width 418 ) 419 { 420 int i; 421 int instrument_string_count = string_diagram_string_count(diagram); 422 double field_width = width / (instrument_string_count - 1); 423 double height = field_width * 4; 424 double y_above_diagram = y + height + field_width / 2 + field_width / 2.5; 425 double vertical_lines_height = height + field_width / 2; 426 if (!pdfioContentSetLineWidth(stream, field_width * 0.09)) { 427 fprintf(stderr, "pdfioContentSetLineWidth failed.\n"); 428 return false; 429 } 430 if (!draw_rectangle(stream, x, y, width, height, STROKE)) { 431 fprintf(stderr, "draw_rectangle failed.\n"); 432 return false; 433 } 434 // from bottom to top draw horizontal lines 435 for (i = 0; i<4; i++) { 436 if (!draw_line(stream, x, y+field_width * (i+1), width, HORIZONTAL)) { 437 fprintf(stderr, "draw_line failed.\n"); 438 return false; 439 } 440 } 441 // from left to right draw vertical lines 442 for (i = 0; i<instrument_string_count; i++) { 443 if (!draw_line(stream, x+field_width*i, y, vertical_lines_height, VERTICAL)) { 444 fprintf(stderr, "draw_line failed.\n"); 445 return false; 446 } 447 } 448 if (diagram->base_fret == 1) { 449 if (!draw_rectangle(stream, x, y+height, width, field_width/2, FILL_AND_STROKE)) { 450 fprintf(stderr, "draw_rectangle failed.\n"); 451 return false; 452 } 453 } else { 454 double base_pos_x; 455 size_t base_size = 5; 456 char base_position[base_size]; 457 base_position[4] = 0; 458 snprintf((char *)&base_position, base_size, "%d", diagram->base_fret); 459 if (diagram->base_fret > 9) { 460 base_pos_x = x - field_width - field_width; 461 } else { 462 base_pos_x = x - field_width - field_width / 3; 463 } 464 if (!pdfioContentSetTextCharacterSpacing(stream, -1.5)) { 465 fprintf(stderr, "pdfioContentSetTextCharacterSpacing failed.\n"); 466 return false; 467 } 468 if (!pdfioContentSetTextFont(stream, "chord-diagram-regular-font", field_width*1.15)) { 469 fprintf(stderr, "pdfioContentSetTextFont failed.\n"); 470 return false; 471 } 472 if (!text_show(stream, !ctx->diagram_font_is_base_font, base_position, base_pos_x, y+field_width*3+field_width*0.1)) { 473 fprintf(stderr, "text_show failed.\n"); 474 return false; 475 } 476 } 477 int8_t fret, finger; 478 for (i = 0; i<instrument_string_count; i++) { 479 fret = diagram->frets[i]; 480 finger = diagram->fingers[i]; 481 if (fret == -1) { 482 if (!draw_x(stream, x+(i*field_width), y_above_diagram, field_width / 4)) { 483 fprintf(stderr, "draw_x failed.\n"); 484 return false; 485 } 486 } else 487 if (fret == 0) { 488 if (!draw_bezier_circle(stream, x+(i*field_width), y_above_diagram, field_width / 4)) { 489 fprintf(stderr, "draw_circle_with_char_inside failed.\n"); 490 return false; 491 } 492 } else 493 if (fret < 5) { 494 if (!draw_circle_with_char_inside(stream, 495 x + i * field_width, 496 y + field_width/2 + field_width * (4 - fret), 497 field_width, 498 finger_to_char(finger) 499 )) { 500 fprintf(stderr, "draw_circle_with_char_inside failed.\n"); 501 return false; 502 } 503 } 504 } 505 pdfio_obj_t *font_obj; 506 double name_width, centered_x; 507 font_obj = out_pdf_fnt_obj_get_by_name(ctx, "chord-diagram-regular-font"); 508 if (!font_obj) { 509 DEBUG("out_pdf_fnt_obj_get_by_name failed."); 510 return false; 511 } 512 name_width = pdfioContentTextMeasure(font_obj, diagram->name, field_width*2.0); 513 centered_x = (width - name_width) / 2; 514 if (!pdfioContentSetTextFont(stream, "chord-diagram-regular-font", field_width*2.0)) { 515 fprintf(stderr, "pdfioContentSetTextFont failed.\n"); 516 return false; 517 } 518 if (!text_show(stream, !ctx->diagram_font_is_base_font, diagram->name, x+centered_x, y_above_diagram + 7.0)) { 519 fprintf(stderr, "text_show failed.\n"); 520 return false; 521 } 522 return true; 523 } 524 525 struct KeyboardDiagram * 526 keyboard_diagram_new(void) 527 { 528 struct KeyboardDiagram *d = emalloc(sizeof(struct KeyboardDiagram)); 529 d->name = NULL; 530 memset(d->keys, -2, sizeof(d->keys)); 531 return d; 532 } 533 534 static struct KeyboardDiagram * 535 keyboard_diagram_copy_all_but_name(struct KeyboardDiagram *diagram) 536 { 537 struct KeyboardDiagram *copy = keyboard_diagram_new(); 538 memcpy(copy->keys, diagram->keys, 24); 539 return copy; 540 } 541 542 static void 543 keyboard_diagram_free(struct KeyboardDiagram *d) 544 { 545 if (!d) { 546 return; 547 } 548 free(d->name); 549 free(d); 550 } 551 552 struct ChordDiagram * 553 chord_diagram_new() 554 { 555 struct ChordDiagram *d = emalloc(sizeof(struct ChordDiagram)); 556 d->show = true; 557 d->color = cho_rgbcolor_new(20, 20, 20); 558 return d; 559 } 560 561 void 562 chord_diagram_free(struct ChordDiagram *d) 563 { 564 if (!d) { 565 return; 566 } 567 free(d->color); 568 switch (d->type) { 569 case CHORD_DIAGRAM_CONTENT_STRING: 570 string_diagram_free(d->u.sd); 571 break; 572 case CHORD_DIAGRAM_CONTENT_KEYBOARD: 573 keyboard_diagram_free(d->u.kd); 574 break; 575 case CHORD_DIAGRAM_CONTENT_CHORD_MAP: 576 chord_map_free(d->u.cm); 577 break; 578 default: 579 } 580 free(d); 581 } 582 583 static struct ChordDiagram * 584 chord_diagram_copy_all_but_name(struct ChordDiagram *diagram) 585 { 586 struct ChordDiagram *copy = emalloc(sizeof(struct ChordDiagram)); 587 copy->show = diagram->show; 588 copy->color = cho_color_copy(diagram->color); 589 copy->type = diagram->type; 590 switch (diagram->type) { 591 case CHORD_DIAGRAM_CONTENT_STRING: 592 copy->u.sd = string_diagram_copy_all_but_name(diagram->u.sd); 593 break; 594 case CHORD_DIAGRAM_CONTENT_KEYBOARD: 595 copy->u.kd = keyboard_diagram_copy_all_but_name(diagram->u.kd); 596 break; 597 default: 598 util_log(NULL, 0, LOG_ERR, "Invalid ChordDiagram type '%d'", diagram->type); 599 free(copy->color); 600 free(copy); 601 return NULL; 602 } 603 return copy; 604 } 605 606 enum ChordDiagramContent 607 chord_diagram_duplicate( 608 struct ChordDiagram *diagram, 609 struct ChordDiagram **custom_diagrams, 610 int custom_diagrams_len, 611 const char *name, 612 const char *chord_to_copy, 613 enum Instrument instrument 614 ) 615 { 616 int d; 617 for (d = custom_diagrams_len-1; d >= 0; d--) { 618 switch (custom_diagrams[d]->type) { 619 case CHORD_DIAGRAM_CONTENT_STRING: 620 if (!strcmp(custom_diagrams[d]->u.sd->name, chord_to_copy)) { 621 diagram->type = CHORD_DIAGRAM_CONTENT_STRING; 622 diagram->u.sd = string_diagram_copy_all_but_name(custom_diagrams[d]->u.sd); 623 diagram->u.sd->name = strdup(name); 624 return CHORD_DIAGRAM_CONTENT_STRING; 625 } 626 break; 627 case CHORD_DIAGRAM_CONTENT_KEYBOARD: 628 if (!strcmp(custom_diagrams[d]->u.kd->name, chord_to_copy)) { 629 diagram->type = CHORD_DIAGRAM_CONTENT_KEYBOARD; 630 diagram->u.kd = keyboard_diagram_copy_all_but_name(custom_diagrams[d]->u.kd); 631 diagram->u.kd->name = strdup(name); 632 return CHORD_DIAGRAM_CONTENT_KEYBOARD; 633 } 634 break; 635 case CHORD_DIAGRAM_CONTENT_CHORD_MAP: 636 if (!strcmp(custom_diagrams[d]->u.cm->name, chord_to_copy)) { 637 diagram->type = CHORD_DIAGRAM_CONTENT_CHORD_MAP; 638 diagram->u.cm = chord_map_new(); 639 diagram->u.cm->display = strdup(custom_diagrams[d]->u.cm->display); 640 diagram->u.cm->name = strdup(name); 641 return CHORD_DIAGRAM_CONTENT_CHORD_MAP; 642 } 643 break; 644 default: 645 } 646 } 647 switch (instrument) { 648 case INSTRUMENT_GUITAR: { 649 size_t i; 650 for (i = 0; i<LENGTH(guitar_diagrams); i++) { 651 if (!strcmp(guitar_diagrams[i].name, chord_to_copy)) { 652 diagram->type = CHORD_DIAGRAM_CONTENT_STRING; 653 diagram->u.sd = string_diagram_copy_all_but_name(&guitar_diagrams[i]); 654 diagram->u.sd->name = strdup(name); 655 return CHORD_DIAGRAM_CONTENT_STRING; 656 } 657 } 658 break; 659 } 660 case INSTRUMENT_KEYBOARD: { 661 break; 662 } 663 case INSTRUMENT_MANDOLIN: { 664 break; 665 } 666 case INSTRUMENT_UKULELE: { 667 break; 668 } 669 } 670 return -1; 671 } 672 673 void 674 chord_diagrams_free(struct ChordDiagram **diagrams) 675 { 676 if (!diagrams) { 677 return; 678 } 679 struct ChordDiagram **d; 680 for (d = diagrams; *d; d++) { 681 chord_diagram_free(*d); 682 } 683 free(diagrams); 684 } 685 686 #ifdef ENABLE_DEBUG 687 void 688 debug_chord_diagram_print(struct ChordDiagram *diagram) 689 { 690 int i; 691 printf("---- CHORD DIAGRAM BEGIN ----\n"); 692 printf("show: %s\n", diagram->show ? "true" : "false"); 693 694 size_t size = 8; 695 char str[size]; 696 // str[7] = 0; 697 snprintf((char *)&str, size, "#%02X%02X%02X", diagram->color->red, diagram->color->green, diagram->color->blue); 698 699 printf("color: %s\n", str); 700 701 switch (diagram->type) { 702 case CHORD_DIAGRAM_CONTENT_STRING: 703 printf("name: %s\n", diagram->u.sd->name); 704 printf("base-fret: %d\n", diagram->u.sd->base_fret); 705 printf("frets: "); 706 for (i = 0; i<12; i++) { 707 printf("%d ", diagram->u.sd->frets[i]); 708 } 709 printf("\n"); 710 printf("fingers: "); 711 for (i = 0; i<12; i++) { 712 printf("%d ", diagram->u.sd->fingers[i]); 713 } 714 printf("\n"); 715 break; 716 case CHORD_DIAGRAM_CONTENT_KEYBOARD: 717 printf("name: %s\n", diagram->u.kd->name); 718 printf("keys: "); 719 for (i = 0; i<24; i++) { 720 printf("%d ", diagram->u.kd->keys[i]); 721 } 722 printf("\n"); 723 break; 724 case CHORD_DIAGRAM_CONTENT_CHORD_MAP: 725 printf("name: %s\n", diagram->u.cm->name); 726 printf("display: %s\n", diagram->u.cm->display); 727 break; 728 default: 729 } 730 printf("---- CHORD DIAGRAM END ------\n"); 731 } 732 #endif /* ENABLE_DEBUG */ 733 734 struct ChordDiagram ** 735 chord_diagrams_create( 736 struct Config *config, 737 struct ChoChord ***chords, 738 struct ChordDiagram **custom_diagrams 739 ) 740 { 741 struct ChordDiagram **diagrams = NULL; 742 struct ChordDiagram **cd; 743 struct ChoChord **c; 744 int d = 0; 745 size_t i; 746 char **names = NULL; 747 char *chord_name = NULL; 748 char *common_chord_name = NULL; 749 char *parsed_chord_name; 750 751 switch (config->output->diagram->instrument) { 752 case INSTRUMENT_GUITAR: 753 for (c = *chords; *c; c++) { 754 // cho_debug_chord_print(*c); 755 parsed_chord_name = (*c)->name; 756 common_chord_name = cho_chord_name_generate_common(*c, config); 757 chord_name = cho_chord_name_generate(*c); 758 for (cd = custom_diagrams; *cd; cd++) { 759 if ( 760 (*cd)->type == CHORD_DIAGRAM_CONTENT_STRING && 761 string_diagram_fret_count((*cd)->u.sd) == 6 && 762 !strcmp(parsed_chord_name, (*cd)->u.sd->name) && 763 !strs_has(names, chord_name) 764 ) { 765 strs_add(&names, chord_name); 766 diagrams = erealloc(diagrams, (d+1) * sizeof(struct ChordDiagram *)); 767 diagrams[d] = chord_diagram_copy_all_but_name(*cd); 768 if (!diagrams[d]) { 769 DEBUG("chord_diagram_copy_all_but_name failed."); 770 goto ERR; 771 } 772 diagrams[d]->u.sd->name = strdup(chord_name); 773 d++; 774 goto NEXT_CHORD; 775 } 776 } 777 for (i = 0; i<LENGTH(guitar_diagrams); i++) { 778 if ( 779 !strcmp(common_chord_name, guitar_diagrams[i].name) && 780 !strs_has(names, chord_name) 781 ) { 782 strs_add(&names, chord_name); 783 diagrams = erealloc(diagrams, (d+1) * sizeof(struct ChordDiagram *)); 784 diagrams[d] = chord_diagram_new(); 785 diagrams[d]->type = CHORD_DIAGRAM_CONTENT_STRING; 786 diagrams[d]->u.sd = string_diagram_copy_all_but_name(&guitar_diagrams[i]); 787 diagrams[d]->u.sd->name = strdup(chord_name); 788 d++; 789 break; 790 } 791 } 792 NEXT_CHORD: 793 free(common_chord_name); 794 free(chord_name); 795 common_chord_name = NULL; 796 chord_name = NULL; 797 } 798 break; 799 case INSTRUMENT_KEYBOARD: 800 break; 801 case INSTRUMENT_MANDOLIN: 802 break; 803 case INSTRUMENT_UKULELE: 804 break; 805 default: 806 util_log(NULL, 0, LOG_ERR, "Invalid Instrument enum value '%d'.", config->output->diagram->instrument); 807 } 808 diagrams = erealloc(diagrams, (d+1) * sizeof(struct ChordDiagram *)); 809 diagrams[d] = NULL; 810 strs_free(names); 811 return diagrams; 812 ERR: 813 free(chord_name); 814 free(common_chord_name); 815 strs_free(names); 816 for (int k = 0; k<d; k++) { 817 chord_diagram_free(diagrams[k]); 818 } 819 free(diagrams); 820 return NULL; 821 } 822 823 bool 824 chord_diagram_draw( 825 struct PDFContext *ctx, 826 pdfio_stream_t *stream, 827 struct ChordDiagram *diagram, 828 double x, 829 double y, 830 double width 831 ) 832 { 833 switch (diagram->type) { 834 case CHORD_DIAGRAM_CONTENT_STRING: 835 if (!string_diagram_draw(ctx, stream, diagram->u.sd, x, y, width)) { 836 DEBUG("draw_string_chord_diagram failed."); 837 return false; 838 } 839 break; 840 /* case CHORD_DIAGRAM_CONTENT_KEYBOARD: 841 util_log(NULL, 0, LOG_TODO, "draw_keyboard_chord_diagram()"); 842 break; 843 case CHORD_DIAGRAM_CONTENT_CHORD_MAP: 844 util_log(NULL, 0, LOG_TODO, "well"); 845 break; */ 846 default: 847 util_log(NULL, 0, LOG_ERR, "These 'enum ChordDiagramContent' values are not yet implemented."); 848 return false; 849 } 850 return true; 851 }