+2002-05-29 Han-Wen <hanwen@cs.uu.nl>
+
+ * ly/engraver-init.ly (TabStaffContext):
+ enable TabStaff by default.
+
+ * Tablature support by Jean-Baptiste Lamy <jiba@@tuxfamily.org>
+
2002-05-28 Jan Nieuwenhuizen <janneke@gnu.org>
* config.hh.in: Remove duplicate DIR_DATADIR entry.
@itemize @bullet
@item @email{tca@@gnu.org, Tom Cato Amundsen},
- cembalo-partita in lilypond, accordion symbols, some lilypond-book.py
+ cembalo-partita in lilypond, accordion symbols, some
+lilypond-book.py
+@item @email{jiba@@tuxfamily.org,Jean-Baptiste Lamy }
+ Tablature support
@item @email{matsb@@s3.kth.se, Mats Bengtsson},
@uref{http://www.s3.kth.se/~matsb/}
lots of testing, fixes, general comments and contributions.
--- /dev/null
+\version "1.3.146"
+
+%{
+
+A sample tablature.
+
+Tablature is done by overriding the note-head formatting function, and
+putting it on a 6-line staff. A special engraver takes care of going
+from string-number + pitch to number.
+
+%}
+
+\score {
+ \notes \context TabStaff { ces'16-2 d'-2 e'8-2 g'2.-3 c'4-1 c''8-5 b'-5 }
+
+ }
static void set_beaming (Grob*,int, Direction d);
static Grob * beam_l (Grob*);
static Grob * first_head (Grob*) ;
+ static Grob * last_head (Grob*) ;
static Drul_array<Grob*> extremal_heads (Grob*);
static Grob * support_head (Grob*) ;
static void add_head (Grob*me, Grob*n);
"calculate the number of semitones of @var{p} from central C.")
{
Pitch *p = unsmob_pitch (pp);
- SCM_ASSERT_TYPE(p, pp, SCM_ARG1, __FUNCTION__, "Pitch");
+ SCM_ASSERT_TYPE(p, pp, SCM_ARG1, __FUNCTION__, "Pitch");
- int q = p->steps ();
+ int q = p->semitone_pitch ();
+
+ // Was :
+ //
+ //int q = p->steps ();
+ //
+ // As the function is called "pitch_semitones", I assume it was a mistake !
+ // Jiba
return gh_int2scm (q);
}
return extremal_heads (me)[-d];
}
+/*
+ The note head opposite to the first head.
+ */
+Grob*
+Stem::last_head (Grob*me)
+{
+ Direction d = get_direction (me);
+ if (!d)
+ return 0;
+ return extremal_heads (me)[d];
+}
+
/*
START is part where stem reaches `last' head.
*/
Direction d = get_direction (me);
- Real y1 = Staff_symbol_referencer::position_f (first_head (me));
+
+ Real y1;
+
+ /*
+ This is required to avoid stems passing in tablature chords...
+ */
+
+
+ /*
+ TODO: make the stem start a direction ?
+
+ */
+ if (to_boolean (me->get_grob_property ("avoid-note-head")))
+ {
+ y1 = Staff_symbol_referencer::position_f (last_head (me));
+ }
+ else
+ {
+ y1 = Staff_symbol_referencer::position_f (first_head (me));
+ }
+
Real y2 = stem_end_position (me);
Interval stem_y (y1 <? y2,y2 >? y1);
--- /dev/null
+/*
+ head-grav.cc -- part of GNU LilyPond
+
+ (c) 1997--2002 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+*/
+#include <ctype.h>
+#include <stdio.h>
+
+#include "rhythmic-head.hh"
+#include "paper-def.hh"
+#include "musical-request.hh"
+#include "dots.hh"
+#include "dot-column.hh"
+#include "staff-symbol-referencer.hh"
+#include "item.hh"
+#include "score-engraver.hh"
+#include "warn.hh"
+
+/**
+ make (guitar-like) tablature note
+ */
+class Tab_note_heads_engraver : public Engraver
+{
+ Link_array<Item> note_p_arr_;
+
+ Link_array<Item> dot_p_arr_;
+ Link_array<Note_req> note_req_l_arr_;
+
+ Link_array<Text_script_req> tabstring_req_arr_;
+
+public:
+ TRANSLATOR_DECLARATIONS(Tab_note_heads_engraver);
+
+protected:
+ virtual void start_translation_timestep ();
+ virtual bool try_music (Music *req_l) ;
+ virtual void process_music ();
+
+ virtual void stop_translation_timestep ();
+};
+
+
+Tab_note_heads_engraver::Tab_note_heads_engraver()
+{
+}
+
+bool
+Tab_note_heads_engraver::try_music (Music *m)
+{
+ if (Note_req * n =dynamic_cast <Note_req *> (m))
+ {
+ note_req_l_arr_.push (n);
+ return true;
+ }
+ else if (Text_script_req * ts = dynamic_cast<Text_script_req*> (m))
+ {
+ if (m->get_mus_property ("text-type") != ly_symbol2scm ("finger")) return false;
+
+ //if (tabstring_req_arr_.size () < note_req_l_arr_.size ()) {
+ tabstring_req_arr_.push (ts);
+ //}
+ return true;
+ }
+ else if (dynamic_cast<Busy_playing_req*> (m))
+ {
+ return note_req_l_arr_.size ();
+ }
+
+ return false;
+}
+
+
+void
+Tab_note_heads_engraver::process_music ()
+{
+ /*
+ for (int i=0; i < tabstring_req_arr_.size (); i++) {
+ Music * tabstring_req = tabstring_req_arr_[i];
+
+ size_t lenp;
+ char* tab_string_as_str = gh_scm2newstr(tabstring_req->get_mus_property ("text"), &lenp);
+ }
+ */
+
+ for (int i=0; i < note_req_l_arr_.size (); i++)
+ {
+ Item * note_p = new Item (get_property ("TabNoteHead"));
+
+ Music * req = note_req_l_arr_[i];
+
+ Music * tabstring_req = tabstring_req_arr_[i];
+
+ size_t lenp;
+ char* tab_string_as_str = gh_scm2newstr(tabstring_req->get_mus_property ("text"), &lenp);
+ int tab_string = atoi(tab_string_as_str);
+
+ Duration dur = *unsmob_duration (req->get_mus_property ("duration"));
+
+ note_p->set_grob_property ("duration-log", gh_int2scm (dur.duration_log ()));
+
+ if (dur.dot_count ())
+ {
+ Item * d = new Item (get_property ("Dots"));
+ Rhythmic_head::set_dots (note_p, d);
+
+ if (dur.dot_count ()
+ != gh_scm2int (d->get_grob_property ("dot-count")))
+ d->set_grob_property ("dot-count", gh_int2scm (dur.dot_count ()));
+
+ d->set_parent (note_p, Y_AXIS);
+ announce_grob (d, SCM_EOL);
+ dot_p_arr_.push (d);
+ }
+
+ int pos = 2 * tab_string - 2; // No tab-note between the string !!!
+ SCM c0 = get_property ("centralCPosition");
+ if (gh_number_p (c0)) pos += gh_scm2int (c0);
+
+ note_p->set_grob_property ("tab-string", gh_int2scm (tab_string));
+
+ note_p->set_grob_property ("staff-position", gh_int2scm (pos));
+ announce_grob (note_p, req->self_scm());
+ note_p_arr_.push (note_p);
+ }
+}
+
+void
+Tab_note_heads_engraver::stop_translation_timestep ()
+{
+ for (int i=0; i < note_p_arr_.size (); i++)
+ {
+ typeset_grob (note_p_arr_[i]);
+ }
+
+ note_p_arr_.clear ();
+ for (int i=0; i < dot_p_arr_.size (); i++)
+ {
+ typeset_grob (dot_p_arr_[i]);
+ }
+ dot_p_arr_.clear ();
+
+ note_req_l_arr_.clear ();
+
+ tabstring_req_arr_.clear ();
+}
+
+void
+Tab_note_heads_engraver::start_translation_timestep ()
+{
+}
+
+
+ENTER_DESCRIPTION(Tab_note_heads_engraver,
+/* descr */ "Generate one or more tablature noteheads from Music of type Note_req.",
+/* creats*/ "TabNoteHead Dots",
+/* acks */ "",
+/* reads */ "centralCPosition",
+/* write */ "");
\accepts "RhythmicStaff"
\accepts "GrandStaff"
\accepts "PianoStaff"
-
+ \accepts "TabStaff"
\accepts "Lyrics"
\accepts "ChordNames"
}
\consists "Span_arpeggio_engraver"
\accepts "Staff"
+ \accepts "TabStaff"
\accepts "StaffContainer"
\accepts "StaffGroup"
\accepts "RhythmicStaff"
\consists "Figured_bass_engraver"
\consistsend "Axis_group_engraver"
}
+
+TabVoiceContext = \translator {
+ \VoiceContext
+ \name "TabVoice"
+ \denies "Thread"
+ \consists "Tab_note_heads_engraver"
+}
+
+TabStaffContext = \translator {
+ \StaffContext
+ \alias "Staff"
+ \name "TabStaff"
+ \denies "Voice"
+ \accepts "TabVoice"
+
+ % 6 strings
+ StaffSymbol \override #'line-count = #6
+ StaffSymbol \override #'staff-space = #1.5
+
+ % One may change the strings tuning as following :
+ % The lenght of the list must be equal to the number of string
+ %TabNoteHead \override #'string-tunings = #'(10 10 10 10 10 10)
+
+ % Special "TAB" clef
+ clefGlyph = #"clefs-tab"
+ clefPosition = #0
+
+ % Don't draw stems over the tabature figures !
+ Stem \override #'avoid-note-head = ##t
+
+ % No accidental in tablature !
+ Accidental = \turnOff
+}
+
\translator { \LyricsVoiceContext }
\translator { \StaffContainerContext }
\translator { \FiguredBassContext }
-
+\translator { \TabStaffContext }
+\translator { \TabVoiceContext }
(meta . ((interfaces . (rhythmic-head-interface font-interface note-head-interface staff-symbol-referencer-interface))))
))
+ (TabNoteHead
+ . (
+ (font-family . roman)
+ (style . default)
+ (molecule-callback . ,tablature-molecule-callback)
+ (Y-offset-callbacks . (,Staff_symbol_referencer::callback))
+ (stem-attachment-function . ,tablature-stem-attachment-function)
+ (string-tunings . (-8 -3 2 7 11 16))
+ (meta . ((interfaces . (rhythmic-head-interface font-interface note-head-interface staff-symbol-referencer-interface))))
+ ))
+
(Glissando
. (
(type . line)
(Y-offset-callbacks . (,Staff_symbol_referencer::callback))
(adjust-if-on-staffline . #t)
(font-family . music)
+ (avoid-note-head . #f)
(meta . ((interfaces . (stem-interface font-interface))))
))
(grob-property-description 'chord-name-function procedure? "DOCME")
(grob-property-description 'minimum-beam-collision-distance number?
"Minimum distance to beam for a rest collision.")
+
+(grob-property-description 'tab-string number? "The tablature string of a TabNoteHead.")
+(grob-property-description 'avoid-note-head boolean? "if set, the stem of a chord does not pass through all note head, but start at the last note head. Used by tablature.")
+(grob-property-description 'string-tunings list? "The strings tuning, in semi-tons from the middle C. Used by tablature.")
;;;; (c) 1998--2001 Jan Nieuwenhuizen <janneke@gnu.org>
;;;; Han-Wen Nienhuys <hanwen@cs.uu.nl>
+; Tablature functions, by Jiba (jiba@tuxfamily.org)
+
+; The TabNoteHead stem attachment function.
+(define (tablature-stem-attachment-function style)
+ (cons 0.0 1.0)
+)
+
+; The TabNoteHead molecule callback.
+; Create a text molecule
+(define (tablature-molecule-callback grob)
+ (let ((molecule (fontify-text
+ (ly-get-default-font grob)
+ (string-append
+ (number->string
+ (- (pitch-semitones (ly-get-mus-property (ly-get-grob-property grob 'cause) 'pitch))
+ (list-ref
+ (ly-get-grob-property grob 'string-tunings)
+ (- (ly-get-grob-property grob 'tab-string)
+ 1 ; remove 1 because list index starts at 0 and guitar string at 1.
+ ))
+ )
+ )
+ )
+ )))
+ molecule ; return the molecule.
+ )
+ )
+
+; end of tablature functions
+
(define (arg->string arg)
(cond ((number? arg) (inexact->string arg 10))