function: compute fret numbers.
* scm/output-lib.scm (string-frets->description) new function.
(fret-board::calc-stencil): new function
* scm/fret-diagrams.scm (fret-diagram-verbose): update doc string.
* scm/define-grobs.scm (all-grob-descriptions): add FretBoard grob.
* lily/include/lily-guile.hh (ly_cxx_vector_to_list): new function.
* lily/tab-note-heads-engraver.cc: cleanups.
* lily/fretboard-engraver.cc: new file
* ly/engraver-init.ly: add FretBoards context
+2006-10-25 Han-Wen Nienhuys <hanwen@lilypond.org>
+
+ * scm/translation-functions.scm (determine-frets-mf): new
+ function: compute fret numbers.
+
+ * scm/output-lib.scm (string-frets->description) new function.
+ (fret-board::calc-stencil): new function
+
+ * scm/fret-diagrams.scm (fret-diagram-verbose): update doc string.
+
+ * scm/define-grobs.scm (all-grob-descriptions): add FretBoard grob.
+
+ * lily/include/lily-guile.hh (ly_cxx_vector_to_list): new function.
+
+ * lily/tab-note-heads-engraver.cc: cleanups.
+
+ * lily/fretboard-engraver.cc: new file
+
+ * ly/engraver-init.ly: add FretBoards context
+
2006-10-24 Joe Neeman <joeneeman@gmail.com>
* lily/grob.cc (pure_relative_y_coordinate)
2006-10-24 Han-Wen Nienhuys <hanwen@lilypond.org>
+ * Documentation/user/lilypond-book.itely (Integrating DocBook and
+ music): patch by Bertalan Fodor for docbook.
+
* Documentation/topdocs/GNUmakefile (LILYPOND_BINARY): use instead
of $(LILYPOND). Prevents lilypond run for .txt files.
--- /dev/null
+/*
+ fretboard-engraver.cc -- part of GNU LilyPond
+
+ (c) 2006 Han-Wen Nienhuys
+*/
+
+#include <cctype>
+#include <cstdio>
+using namespace std;
+
+#include "context.hh"
+#include "item.hh"
+#include "engraver.hh"
+#include "pitch.hh"
+#include "stream-event.hh"
+#include "warn.hh"
+
+#include "translator.icc"
+
+/**
+ make (guitar-like) tablature note
+*/
+class Fretboard_engraver : public Engraver
+{
+ Item *fret_board_;
+
+ vector<Stream_event*> note_events_;
+ vector<Stream_event*> tabstring_events_;
+public:
+ TRANSLATOR_DECLARATIONS (Fretboard_engraver);
+
+protected:
+ DECLARE_TRANSLATOR_LISTENER (note);
+ DECLARE_TRANSLATOR_LISTENER (string_number);
+ void process_music ();
+
+ void stop_translation_timestep ();
+};
+
+Fretboard_engraver::Fretboard_engraver ()
+{
+ fret_board_ = 0;
+}
+
+IMPLEMENT_TRANSLATOR_LISTENER (Fretboard_engraver, note);
+void
+Fretboard_engraver::listen_note (Stream_event *ev)
+{
+ note_events_.push_back (ev);
+}
+
+IMPLEMENT_TRANSLATOR_LISTENER (Fretboard_engraver, string_number);
+void
+Fretboard_engraver::listen_string_number (Stream_event *ev)
+{
+ tabstring_events_.push_back (ev);
+}
+
+void
+Fretboard_engraver::process_music ()
+{
+ if (!note_events_.size ())
+ return ;
+
+ fret_board_ = make_item ("FretBoard", note_events_[0]->self_scm ());
+
+ SCM proc = get_property ("noteToFretFunction");
+ if (ly_is_procedure (proc))
+ {
+ scm_call_4 (proc,
+ context ()->self_scm (),
+ fret_board_->self_scm (),
+
+ ly_cxx_vector_to_list (note_events_),
+ ly_cxx_vector_to_list (tabstring_events_));
+ }
+}
+
+void
+Fretboard_engraver::stop_translation_timestep ()
+{
+ fret_board_ = 0;
+ note_events_.clear ();
+ tabstring_events_.clear ();
+}
+
+ADD_TRANSLATOR (Fretboard_engraver,
+ /* doc */ "Generate one or more tablature noteheads from event of type NoteEvent.",
+ /* create */
+ "FretBoard "
+ ,
+
+ /* read */
+ "stringTunings "
+ "minimumFret "
+ "tablatureFormat "
+ "highStringOne "
+ ,
+ /* write */ "");
+
inline bool ly_scm2bool (SCM x) { return SCM_NFALSEP (x); }
inline char ly_scm2char (SCM x) { return SCM_CHAR (x); }
-inline unsigned long ly_length (SCM x)
-{
- return scm_num2ulong (scm_length (x), 0, "ly_length");
-}
inline SCM ly_bool2scm (bool x) { return SCM_BOOL (x); }
inline SCM ly_append2 (SCM x1, SCM x2)
inline SCM ly_cdr (SCM x) { return SCM_CDR (x); }
inline bool ly_is_pair (SCM x) { return SCM_I_CONSP (x); }
+
+
+#include "std-vector.hh"
+
+template<class T>
+SCM
+ly_cxx_vector_to_list (vector<T> const &src)
+{
+ SCM l = SCM_EOL;
+ for (vsize i = src.size (); i --; )
+ l = scm_cons (src[i]->self_scm (), l);
+
+ return l;
+}
+
+
#endif /* LILY_GUILE_HH */
{
Grob *me = unsmob_grob (smob);
if (Semi_tie_column::has_interface (me->get_parent (Y_AXIS)))
- me->get_parent (Y_AXIS)->get_property("positioning-done");
+ {
+ me->get_parent (Y_AXIS)->get_property("positioning-done");
+ }
else
{
programming_error ("lv tie without Semi_tie_column");
#include <cctype>
#include <cstdio>
+
+#include "engraver.hh"
+
using namespace std;
-#include "dot-column.hh"
-#include "dots.hh"
#include "duration.hh"
#include "item.hh"
#include "output-def.hh"
#include "pitch.hh"
#include "rhythmic-head.hh"
-#include "score-engraver.hh"
-#include "staff-symbol-referencer.hh"
#include "stream-event.hh"
#include "warn.hh"
for (vsize i = 0; i < note_events_.size (); i++)
{
SCM stringTunings = get_property ("stringTunings");
- int number_of_strings = ((int) ly_length (stringTunings));
+ int number_of_strings = scm_ilength (stringTunings);
bool high_string_one = to_boolean (get_property ("highStringOne"));
Stream_event *event = note_events_[i];
\grobdescriptions #all-grob-descriptions
}
+
+\context {
+ \type "Engraver_group"
+ \name "FretBoards"
+
+ \consists "Output_property_engraver"
+
+ \consists "Axis_group_engraver"
+ \consists "Fretboard_engraver"
+ \consists "Separating_line_group_engraver"
+ \consists "Font_size_engraver"
+}
\context {
\type "Engraver_group"
\name "Staff"
\consists "Separating_line_group_engraver"
\consists "Dot_column_engraver"
- %% perhaps move to Voice context?
+ %% perhaps move to Voice context?
\consists "Ottava_spanner_engraver"
\consists "Clef_engraver"
\consists "Key_engraver"
\defaultchild "Staff"
+ \accepts "FretBoards"
\accepts "Staff"
\accepts "RhythmicStaff"
\accepts "TabStaff"
\accepts "Devnull"
\accepts "NoteNames"
\accepts "FiguredBass"
-
+
+
+ noteToFretFunction = #determine-frets
soloText = #"Solo"
soloIIText = #"Solo II"
aDueText = #"a2"
side-position-interface
self-alignment-interface
item-interface))))))
+ (FretBoard
+ . ((stencil . ,fret-board::calc-stencil)
+ (meta . ((class . Item)
+ (interfaces . (fret-board-interface
+ font-interface
+ ))))
+ ))
(Glissando
. (
(style . line)
For example,
@example
- \\markup \\fret-diagram #'((mute 6) (mute 5) (open 4)
+ \\markup \\fret-diagram-verbose #'((mute 6) (mute 5) (open 4)
(place-fret 3 2) (place-fret 2 3) (place-fret 1 2))
@end example
(define-public (lyric-text::calc-text grob)
(ly:event-property (event-cause grob) 'text))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; fret boards
+
+(define (string-frets->description string-frets string-count)
+ (let*
+ ((desc (list->vector
+ (map (lambda (x) (list 'mute (1+ x)))
+ (iota string-count)))))
+
+ (for-each (lambda (sf)
+ (let*
+ ((string (car sf))
+ (fret (cdr sf)))
+
+
+ (vector-set! desc (1- string)
+ (if (= 0 fret)
+ (list 'open string)
+ (list 'place-fret string fret)))
+ ))
+ string-frets)
+ (vector->list desc)))
+
+(define-public (fret-board::calc-stencil grob)
+ (let* ((string-frets (ly:grob-property grob 'string-frets))
+ (string-count (ly:grob-property grob 'string-count))
+ (layout (ly:grob-layout grob))
+ (defs (ly:output-def-lookup layout 'text-font-defaults))
+ (props (ly:grob-alist-chain grob defs)))
+
+ (make-fret-diagram layout props
+ (string-frets->description string-frets 6))))
))
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; fret diagrams
+
+(define-public (determine-frets context grob notes string-numbers)
+ (define (ensure-number a b)
+ (if (number? a)
+ a
+ b))
+(let*
+ ((tunings (ly:context-property context 'stringTunings))
+ (minimum-fret (ensure-number
+ (ly:context-property context 'minimumFret) 0))
+ (string-frets (determine-frets-mf notes string-numbers
+ minimum-fret
+ tunings)))
+
+
+ (set! (ly:grob-property grob 'string-count) (length tunings))
+ (set! (ly:grob-property grob 'string-frets) string-frets)
+
+ ))
+
+(define-public (determine-frets-mf notes string-numbers
+ minimum-fret
+ tunings)
+
+ (define (calc-fret pitch string tuning)
+ (- (ly:pitch-semitones pitch) (list-ref tuning (1- string))))
+
+ (define (note-pitch a)
+ (ly:event-property a 'pitch))
+
+ (define (note-pitch<? a b)
+ (ly:pitch<? (note-pitch a)
+ (note-pitch b)))
+
+ (define (note-ev-string ev)
+ (let* ((articulations (ly:event-property ev 'articulations))
+ (string-found #f))
+
+ (map (lambda (art)
+ (let*
+ ((num (ly:event-property art 'string-number)))
+
+ (if (number? num)
+ (set! string-found num))))
+ articulations)
+ string-found))
+
+ (let*
+ ((free-strings (map 1+ (iota (length tunings))))
+ (del-string (lambda (string)
+ (if (number? string)
+ (set! free-strings
+ (delete string free-strings)))))
+ (string-qualifies (lambda (string pitch)
+ (and (>= (calc-fret pitch string tunings)
+ minimum-fret))))
+ (string-frets '())
+ (set-fret (lambda (note string)
+ (set! string-frets
+ (acons string
+ (calc-fret (ly:event-property note 'pitch)
+ string tunings)
+ string-frets))
+ (del-string string)
+ ))
+
+
+ )
+
+ (for-each (lambda (note)
+ (del-string (note-ev-string note)))
+ notes)
+
+
+ (for-each
+ (lambda (note)
+ (if (note-ev-string note)
+ (set-fret note (note-ev-string note))
+ (let*
+ ((string (find (lambda (string) (string-qualifies string
+ (note-pitch note)))
+ (reverse free-strings))))
+
+ (set-fret note string))))
+ (sort notes note-pitch<?))
+
+
+ (display string-frets)
+
+
+ string-frets))
+