diff options
Diffstat (limited to 'Build/source/texk/gregorio/gregorio-4.0.0-beta2/src/gabc/gabc-elements-determination.c')
-rw-r--r-- | Build/source/texk/gregorio/gregorio-4.0.0-beta2/src/gabc/gabc-elements-determination.c | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/Build/source/texk/gregorio/gregorio-4.0.0-beta2/src/gabc/gabc-elements-determination.c b/Build/source/texk/gregorio/gregorio-4.0.0-beta2/src/gabc/gabc-elements-determination.c new file mode 100644 index 00000000000..eefdc86e49f --- /dev/null +++ b/Build/source/texk/gregorio/gregorio-4.0.0-beta2/src/gabc/gabc-elements-determination.c @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2006-2015 The Gregorio Project (see CONTRIBUTORS.md) + * + * This file is part of Gregorio. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "config.h" +#include <stdio.h> +#include "bool.h" +#include "struct.h" +#include "messages.h" + +#include "gabc.h" + +/* + * + * two inline functions that will be useful in the future: they are the tests + * to put in a if statement to determine if a glyph type is puncta incliata + * ascendens or descendens + * + */ + +static __inline bool is_puncta_ascendens(char glyph) +{ + return glyph == G_2_PUNCTA_INCLINATA_ASCENDENS + || glyph == G_3_PUNCTA_INCLINATA_ASCENDENS + || glyph == G_4_PUNCTA_INCLINATA_ASCENDENS + || glyph == G_5_PUNCTA_INCLINATA_ASCENDENS + || glyph == G_PUNCTUM_INCLINATUM; +} + +static __inline bool is_puncta_descendens(char glyph) +{ + return glyph == G_2_PUNCTA_INCLINATA_DESCENDENS + || glyph == G_3_PUNCTA_INCLINATA_DESCENDENS + || glyph == G_4_PUNCTA_INCLINATA_DESCENDENS + || glyph == G_5_PUNCTA_INCLINATA_DESCENDENS + || glyph == G_PUNCTUM_INCLINATUM; +} + +/* + * + * A function that will be called several times: it adds an element to the + * current element current_element: the current_element in the determination, + * it will be updated to the element that we will add first_glyph: the + * first_glyph of the element that we will add current_glyph: the last glyph + * that will be in the element + * + */ + +static void close_element(gregorio_element **current_element, + gregorio_glyph **const first_glyph, + const gregorio_glyph *const current_glyph) +{ + gregorio_add_element(current_element, *first_glyph); + if (*first_glyph && (*first_glyph)->previous) { + (*first_glyph)->previous->next = NULL; + (*first_glyph)->previous = NULL; + } + *first_glyph = current_glyph->next; +} + +/* + * + * inline function to automatically do two or three things + * + */ +static __inline void cut_before(gregorio_glyph *current_glyph, + gregorio_glyph **first_glyph, + gregorio_glyph **previous_glyph, + gregorio_element **current_element) +{ + if (*first_glyph != current_glyph) { + close_element(current_element, first_glyph, current_glyph); + /* yes, this is changing value close_element sets for first_glyph */ + *first_glyph = current_glyph; + *previous_glyph = current_glyph; + } +} + +/* + * + * The big function of the file, but rather simple I think. + * + */ + +static gregorio_element *gabc_det_elements_from_glyphs( + gregorio_glyph *current_glyph) +{ + /* the last element we have successfully added to the list of elements */ + gregorio_element *current_element = NULL; + /* the first element, that we will return at the end. We have to consider + * it because the gregorio_element struct does not have previous_element + * element. */ + gregorio_element *first_element = NULL; + /* the first_glyph of the element that we are currently determining */ + gregorio_glyph *first_glyph = current_glyph; + /* the last real (GRE_GLYPH) that we have processed, often the same as + * first_glyph */ + gregorio_glyph *previous_glyph = current_glyph; + /* a char that is necessary to determine some cases */ + bool do_not_cut = false; + /* a char that is necesarry to determine the type of the current_glyph */ + char current_glyph_type; + + if (!current_glyph) { + return NULL; + } + /* first we go to the first glyph in the chained list of glyphs (maybe to + * suppress ?) */ + gregorio_go_to_first_glyph(¤t_glyph); + + while (current_glyph) { + if (current_glyph->type != GRE_GLYPH) { + /* we ignore flats and naturals, except if they are alone */ + if (current_glyph->type == GRE_NATURAL + || current_glyph->type == GRE_FLAT + || current_glyph->type == GRE_SHARP) { + if (!current_glyph->next) { + first_element = current_element; + close_element(¤t_element, &first_glyph, current_glyph); + } + current_glyph = current_glyph->next; + continue; + } + /* we must not cut after a zero_width_space */ + if (current_glyph->type == GRE_SPACE + && current_glyph->u.misc.unpitched.info.space == SP_ZERO_WIDTH) { + if (!current_glyph->next) { + close_element(¤t_element, &first_glyph, current_glyph); + } + current_glyph = current_glyph->next; + do_not_cut = true; + continue; + } + /* we must not cut after a zero_width_space */ + if (current_glyph->type == GRE_TEXVERB_GLYPH) { + if (!current_glyph->next) { + close_element(¤t_element, &first_glyph, current_glyph); + } + current_glyph = current_glyph->next; + continue; + } + /* clef change or space or end of line */ + cut_before(current_glyph, &first_glyph, &previous_glyph, + ¤t_element); + /* if statement to make neumatic cuts not appear in elements, as + * there is always one between elements */ + if (current_glyph->type != GRE_SPACE + || current_glyph->u.misc.unpitched.info.space != SP_NEUMATIC_CUT) + /* clef change or space other thant neumatic cut */ + { + if (!first_element) { + first_element = current_element; + } + gregorio_add_misc_element(¤t_element, current_glyph->type, + current_glyph->u.misc, + current_glyph->texverb); + } + first_glyph = current_glyph->next; + previous_glyph = current_glyph->next; + current_glyph->texverb = NULL; + gregorio_free_one_glyph(¤t_glyph); + continue; + } + + if (is_puncta_ascendens(current_glyph->type)) { + current_glyph_type = G_PUNCTA_ASCENDENS; + } else { + if (is_puncta_descendens(current_glyph->type)) { + current_glyph_type = G_PUNCTA_DESCENDENS; + } else { + current_glyph_type = current_glyph->type; + } + } + switch (current_glyph_type) { + case G_PUNCTA_ASCENDENS: + if (!do_not_cut) { + cut_before(current_glyph, &first_glyph, &previous_glyph, + ¤t_element); + do_not_cut = true; + } else { + previous_glyph = current_glyph; + } + break; + case G_PUNCTA_DESCENDENS: + /* we don't cut before, so we don't do anything */ + if (do_not_cut) { + do_not_cut = false; + } + break; + case G_ONE_NOTE: + if (current_glyph->u.notes.first_note + && (current_glyph->u.notes.first_note->u.note.shape == S_STROPHA + || current_glyph->u.notes.first_note->u.note.shape == S_VIRGA + || current_glyph->u.notes.first_note->u.note.shape == S_VIRGA_REVERSA)) { + /* we determine the last pitch */ + char last_pitch; + gregorio_note *tmp_note; + tmp_note = previous_glyph->u.notes.first_note; + while (tmp_note->next) { + tmp_note = tmp_note->next; + } + last_pitch = tmp_note->u.note.pitch; + if (current_glyph->u.notes.first_note->u.note.pitch == last_pitch) { + previous_glyph = current_glyph; + break; + } + } + /* else we fall in the default case */ + default: + if (do_not_cut) { + do_not_cut = false; + } else { + cut_before(current_glyph, &first_glyph, &previous_glyph, + ¤t_element); + } + } + /* + * we must determine the first element, that we will return + */ + if (!first_element && current_element) { + first_element = current_element; + } + if (!current_glyph->next) { + close_element(¤t_element, &first_glyph, current_glyph); + } + current_glyph = current_glyph->next; + } /* end of while */ + + /* + * we must determine the first element, that we will return + */ + if (!first_element && current_element) { + first_element = current_element; + } + return first_element; +} + +/* + * + * Two "hat" functions, they permit to have a good API. They amost don't do + * anything except calling the det_elements_from_glyphs. + * + * All those functions change the current_key, according to the possible new + * values (with key changes) + * + */ + +static gregorio_element *gabc_det_elements_from_notes( + gregorio_note *current_note, int *current_key) +{ + gregorio_element *final = NULL; + gregorio_glyph *tmp = gabc_det_glyphs_from_notes(current_note, current_key); + final = gabc_det_elements_from_glyphs(tmp); + return final; +} + +gregorio_element *gabc_det_elements_from_string(char *const str, int *const current_key, + char *macros[10], gregorio_scanner_location *const loc) +{ + gregorio_element *final; + gregorio_note *tmp; + tmp = gabc_det_notes_from_string(str, macros, loc); + final = gabc_det_elements_from_notes(tmp, current_key); + return final; +} + |