From 5cda9afcf33032bd953c9fc1dd147822177cdddb Mon Sep 17 00:00:00 2001 From: Carl Sorensen Date: Sat, 10 Apr 2010 20:27:21 -0600 Subject: [PATCH] Rationalize string number handling for notes and chords Enable the use of both articulations and events for handling string numbers, while still allowing only some notes to have string numbers. Create articulations.cc to house the common code used by both tab-note-heads-engraver and fretboards-engraver to get string numbers from the music stream. This same code can be used for string-bend articulations and events. Create a regression test to demonstrate that the code will work with string numbers partially specified. --- input/regression/tablature.ly | 3 +- lily/articulations.cc | 85 ++++++++++++++++++++++++++++++++++ lily/fretboard-engraver.cc | 78 ++++++++----------------------- lily/include/articulations.hh | 31 +++++++++++++ lily/tab-note-heads-engraver.cc | 100 ++++++++++++---------------------------- 5 files changed, 167 insertions(+), 130 deletions(-) create mode 100644 lily/articulations.cc create mode 100644 lily/include/articulations.hh diff --git a/input/regression/tablature.ly b/input/regression/tablature.ly index 0c631e87a1..01b418c6ca 100644 --- a/input/regression/tablature.ly +++ b/input/regression/tablature.ly @@ -16,8 +16,9 @@ partition = { \key e \major - <> + \5\4 + \5 } diff --git a/lily/articulations.cc b/lily/articulations.cc new file mode 100644 index 0000000000..e2c16d3007 --- /dev/null +++ b/lily/articulations.cc @@ -0,0 +1,85 @@ +/* + This file is part of LilyPond, the GNU music typesetter. + + Copyright (C) 2010 Carl Sorensen + + LilyPond 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. + + LilyPond 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 LilyPond. If not, see . +*/ +#include "engraver.hh" + +#include "articulations.hh" +#include "stream-event.hh" +#include "warn.hh" +#include "context.hh" + +/* + Return an articulation list given a note_events vector and an + articulation_events vector. + + This is necessary, because the articulations come as events if + they are entered outside of a chord structure, and as articulations + if they are inside the chord structure. So potentially we need to + combine the two types. +*/ + +SCM +articulation_list (vector note_events, + vector articulation_events, + char const *articulation_name) +{ + vector string_events; + SCM articulations = SCM_EOL; + vsize j = 0; + + for (vsize i = 0; i < note_events.size (); i++) + { + + Stream_event *event = note_events[i]; + + Stream_event *articulation_event = 0; + + /* + For notes inside a chord construct, string indications are + stored as articulations on the note, so we check through + the notes + */ + for (SCM s = event->get_property ("articulations"); + !articulation_event && scm_is_pair (s); s = scm_cdr (s)) + { + Stream_event *art = unsmob_stream_event (scm_car (s)); + + if (art->in_event_class (articulation_name)) + articulation_event = art; + } + + /* + For string indications listed outside a chord construct, + a string_number_event is generated, so if there was no string + in the articulations, we check for string events outside + the chord construct + */ + if (!articulation_event && j < articulation_events.size ()) + { + articulation_event = articulation_events[j]; + if (j + 1 < articulation_events.size ()) + j++; + } + articulations = scm_cons ((articulation_event + ? articulation_event->self_scm () + : SCM_EOL), + articulations); + } + + return (scm_reverse (articulations)); +} diff --git a/lily/fretboard-engraver.cc b/lily/fretboard-engraver.cc index f6c7601dfa..4cbd08578c 100644 --- a/lily/fretboard-engraver.cc +++ b/lily/fretboard-engraver.cc @@ -21,6 +21,7 @@ #include using namespace std; +#include "articulations.hh" #include "context.hh" #include "item.hh" #include "engraver.hh" @@ -37,15 +38,15 @@ class Fretboard_engraver : public Engraver { Item *fret_board_; - vector note_events_; - vector tabstring_events_; + vector note_events_; + vector tabstring_events_; public: TRANSLATOR_DECLARATIONS (Fretboard_engraver); protected: void stop_translation_timestep (); void process_music (); - virtual void derived_mark() const; + virtual void derived_mark () const; DECLARE_TRANSLATOR_LISTENER (note); DECLARE_TRANSLATOR_LISTENER (string_number); @@ -53,7 +54,6 @@ private: SCM last_fret_notes_; }; - void Fretboard_engraver::derived_mark () const { @@ -84,60 +84,20 @@ void Fretboard_engraver::process_music () { if (!note_events_.size ()) - return ; - - // Ugh -- copied from tab-note-heads-engraver; need to resolve - vsize j = 0; - - vector string_events; - - for (vsize i = 0; i < note_events_.size (); i++) - { - - Stream_event *event = note_events_[i]; - - Stream_event *tabstring_event = 0; - - /* - For notes inside a chord construct, string indications are - stored as articulations on the note, so we check through - the notes - */ - for (SCM s = event->get_property ("articulations"); - !tabstring_event && scm_is_pair (s); s = scm_cdr (s)) - { - Stream_event *art = unsmob_stream_event (scm_car (s)); - - if (art->in_event_class ("string-number-event")) - tabstring_event = art; - } - - /* - For string indications listed outside a chord construct, - a string_number_event is generated, so if there was no string - in the articulations, we check for string events outside - the chord construct - */ - if (!tabstring_event && j < tabstring_events_.size ()) - { - tabstring_event = tabstring_events_[j]; - if (j + 1 < tabstring_events_.size ()) - j++; - } - if (tabstring_event) - string_events.push_back (tabstring_event); - } - // end of copied code + return; + SCM tab_strings = articulation_list (note_events_, + tabstring_events_, + "string-number-event"); fret_board_ = make_item ("FretBoard", note_events_[0]->self_scm ()); SCM fret_notes = ly_cxx_vector_to_list (note_events_); SCM proc = get_property ("noteToFretFunction"); if (ly_is_procedure (proc)) - scm_call_4 (proc, - context ()->self_scm (), - fret_notes, - ly_cxx_vector_to_list (string_events), - fret_board_->self_scm ()); + scm_call_4 (proc, + context ()->self_scm (), + fret_notes, + tab_strings, + fret_board_->self_scm ()); SCM changes = get_property ("chordChanges"); if (to_boolean (changes) && scm_is_pair (last_fret_notes_) && ly_is_equal (last_fret_notes_, fret_notes)) @@ -156,21 +116,21 @@ Fretboard_engraver::stop_translation_timestep () ADD_TRANSLATOR (Fretboard_engraver, /* doc */ - "Generate fret diagram from one or more events of type" + "Generate fret diagram from one or more events of type" " @code{NoteEvent}.", /* create */ "FretBoard ", /* read */ - "chordChanges " + "chordChanges " "highStringOne " - "maximumFretStretch " + "maximumFretStretch " "minimumFret " - "noteToFretFunction " - "predefinedDiagramTable " + "noteToFretFunction " + "predefinedDiagramTable " "stringTunings " - "tablatureFormat ", + "tablatureFormat ", /* write */ "" diff --git a/lily/include/articulations.hh b/lily/include/articulations.hh new file mode 100644 index 0000000000..e590b32b4d --- /dev/null +++ b/lily/include/articulations.hh @@ -0,0 +1,31 @@ +/* + This file is part of LilyPond, the GNU music typesetter. + + Copyright (C) 2010 Carl Sorensen + + LilyPond 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. + + LilyPond 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 LilyPond. If not, see . +*/ + +#ifndef ARTICULATIONS_HH +#define ARTICULATIONS_HH + +#include "lily-guile.hh" +#include "stream-event.hh" + +SCM articulation_list (vector notes, + vector articulations, + char const *articulation_name); + +#endif /* ARTICULATIONS_HH */ + diff --git a/lily/tab-note-heads-engraver.cc b/lily/tab-note-heads-engraver.cc index e9c99d12a8..91a3ba3fc7 100644 --- a/lily/tab-note-heads-engraver.cc +++ b/lily/tab-note-heads-engraver.cc @@ -24,6 +24,7 @@ using namespace std; +#include "articulations.hh" #include "duration.hh" #include "item.hh" #include "output-def.hh" @@ -40,10 +41,10 @@ using namespace std; */ class Tab_note_heads_engraver : public Engraver { - vector notes_; + vector notes_; - vector note_events_; - vector tabstring_events_; + vector note_events_; + vector tabstring_events_; public: TRANSLATOR_DECLARATIONS (Tab_note_heads_engraver); @@ -76,58 +77,17 @@ Tab_note_heads_engraver::listen_string_number (Stream_event *ev) void Tab_note_heads_engraver::process_music () { - vsize j = 0; - - vector string_events; - - for (vsize i = 0; i < note_events_.size (); i++) - { - - Stream_event *event = note_events_[i]; - - Stream_event *tabstring_event = 0; - - /* - For notes inside a chord construct, string indications are - stored as articulations on the note, so we check through - the notes - */ - for (SCM s = event->get_property ("articulations"); - !tabstring_event && scm_is_pair (s); s = scm_cdr (s)) - { - Stream_event *art = unsmob_stream_event (scm_car (s)); - - if (art->in_event_class ("string-number-event")) - tabstring_event = art; - } - - /* - For string indications listed outside a chord construct, - a string_number_event is generated, so if there was no string - in the articulations, we check for string events outside - the chord construct - */ - if (!tabstring_event && j < tabstring_events_.size ()) - { - tabstring_event = tabstring_events_[j]; - if (j + 1 < tabstring_events_.size ()) - j++; - } - if (tabstring_event) - string_events.push_back (tabstring_event); - } - + SCM tab_strings = articulation_list (note_events_, + tabstring_events_, + "string-number-event"); SCM tab_notes = ly_cxx_vector_to_list (note_events_); - SCM tab_strings = SCM_EOL; - if (string_events.size ()) - tab_strings = ly_cxx_vector_to_list (string_events); SCM proc = get_property ("noteToFretFunction"); SCM string_fret_finger = SCM_EOL; if (ly_is_procedure (proc)) string_fret_finger = scm_call_3 (proc, - context ()->self_scm (), - tab_notes, - tab_strings); + context ()->self_scm (), + tab_notes, + tab_strings); SCM note_entry = SCM_EOL; SCM string_number = SCM_EOL; SCM fret = SCM_EOL; @@ -140,23 +100,23 @@ Tab_note_heads_engraver::process_music () vsize index; if (string_fret_finger != SCM_EOL) - for (vsize i=0; i < fret_count; i++) + for (vsize i = 0; i < fret_count; i++) { - note_entry = scm_list_ref (string_fret_finger, scm_from_int (i)); - string_number = scm_car (note_entry); - fret = scm_cadr (note_entry); - fret_label = scm_call_3 (fret_procedure, - context ()->self_scm (), - string_number, - fret); - index = length_changed ? 0 : i; - Item *note = make_item ("TabNoteHead", note_events_[index]->self_scm ()); - note->set_property ("text", fret_label); - staff_position = scm_call_2 (staff_line_procedure, - context ()->self_scm (), - string_number); - note->set_property ("staff-position", staff_position); - notes_.push_back (note); + note_entry = scm_list_ref (string_fret_finger, scm_from_int (i)); + string_number = scm_car (note_entry); + fret = scm_cadr (note_entry); + fret_label = scm_call_3 (fret_procedure, + context ()->self_scm (), + string_number, + fret); + index = length_changed ? 0 : i; + Item *note = make_item ("TabNoteHead", note_events_[index]->self_scm ()); + note->set_property ("text", fret_label); + staff_position = scm_call_2 (staff_line_procedure, + context ()->self_scm (), + string_number); + note->set_property ("staff-position", staff_position); + notes_.push_back (note); } } @@ -181,12 +141,12 @@ ADD_TRANSLATOR (Tab_note_heads_engraver, "highStringOne " "middleCPosition " "minimumFret " - "noteToFretFunction " + "noteToFretFunction " "stringOneTopmost " "stringTunings " - "tablatureFormat " - "tabStaffLineLayoutFunction ", + "tablatureFormat " + "tabStaffLineLayoutFunction ", /* write */ "" - ); + ); -- 2.11.4.GIT