]> git.donarmstrong.com Git - lilypond.git/commitdiff
Rationalize string number handling for notes and chords
authorCarl Sorensen <c_sorensen@byu.edu>
Sun, 11 Apr 2010 02:27:21 +0000 (20:27 -0600)
committerFrancisco Vila <francisco.vila@hispalinux.es>
Fri, 16 Apr 2010 11:24:58 +0000 (13:24 +0200)
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
lily/articulations.cc [new file with mode: 0644]
lily/fretboard-engraver.cc
lily/include/articulations.hh [new file with mode: 0644]
lily/tab-note-heads-engraver.cc

index 0c631e87a14e24e3e6412e66ba90cc2ad5d991e0..01b418c6cac461ca72510ee3c78654b08d58851b 100644 (file)
@@ -16,8 +16,9 @@ partition =  {
   \key e \major
   <e\5 dis'\4>
   <e dis'>
-  <<e\5 dis'\4>>
+  <e dis'\4>
   <e dis'>\5\4
+  <e dis'\4>\5
 }
 
 
diff --git a/lily/articulations.cc b/lily/articulations.cc
new file mode 100644 (file)
index 0000000..e2c16d3
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+  This file is part of LilyPond, the GNU music typesetter.
+
+  Copyright (C) 2010 Carl Sorensen <c_sorensen@byu.edu>
+
+  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 <http://www.gnu.org/licenses/>.
+*/
+#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<Stream_event *> note_events,
+                  vector<Stream_event *> articulation_events,
+                  char const *articulation_name)
+{
+  vector<Stream_event *> 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));
+}
index f6c7601dfa551e64fde09f230993ee674ce5f520..4cbd08578c8db8cd5fd94af599ee7a118ba78198 100644 (file)
@@ -21,6 +21,7 @@
 #include <cstdio>
 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<Stream_event*> note_events_;
-  vector<Stream_event*> tabstring_events_;
+  vector<Stream_event *> note_events_;
+  vector<Stream_event *> 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<Stream_event *> 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 (file)
index 0000000..e590b32
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+  This file is part of LilyPond, the GNU music typesetter.
+
+  Copyright (C) 2010 Carl Sorensen <c_sorensen@byu.edu>
+
+  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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef ARTICULATIONS_HH
+#define ARTICULATIONS_HH
+
+#include "lily-guile.hh"
+#include "stream-event.hh"
+
+SCM articulation_list (vector<Stream_event *> notes,
+                      vector<Stream_event *> articulations,
+                      char const *articulation_name);
+
+#endif /* ARTICULATIONS_HH */
+
index e9c99d12a8860f8d0c4821b5f266a9964ec0460f..91a3ba3fc701cd7e2c754a9feb1206196627f496 100644 (file)
@@ -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<Item*> notes_;
+  vector<Item *> notes_;
 
-  vector<Stream_event*> note_events_;
-  vector<Stream_event*> tabstring_events_;
+  vector<Stream_event *> note_events_;
+  vector<Stream_event *> 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<Stream_event *> 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 */ ""
-               );
+                );