/* This file is part of LilyPond, the GNU music typesetter. Copyright (C) 2006--2020 Han-Wen Nienhuys 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 "articulations.hh" #include "context.hh" #include "item.hh" #include "engraver.hh" #include "pitch.hh" #include "stream-event.hh" #include "warn.hh" #include "translator.icc" #include #include using std::vector; /** make (guitar-like) tablature note */ class Fretboard_engraver : public Engraver { Item *fret_board_; vector note_events_; vector tabstring_events_; vector fingering_events_; public: TRANSLATOR_DECLARATIONS (Fretboard_engraver); protected: void stop_translation_timestep (); void process_music (); void derived_mark () const override; void listen_note (Stream_event *); void listen_string_number (Stream_event *); void listen_fingering (Stream_event *); private: SCM last_placements_; }; void Fretboard_engraver::derived_mark () const { scm_gc_mark (last_placements_); } Fretboard_engraver::Fretboard_engraver (Context *c) : Engraver (c) { fret_board_ = 0; last_placements_ = SCM_BOOL_F; } void Fretboard_engraver::listen_note (Stream_event *ev) { note_events_.push_back (ev); } void Fretboard_engraver::listen_string_number (Stream_event *ev) { tabstring_events_.push_back (ev); } void Fretboard_engraver::listen_fingering (Stream_event *ev) { fingering_events_.push_back (ev); } void Fretboard_engraver::process_music () { if (!note_events_.size ()) return; SCM tab_strings = articulation_list (note_events_, tabstring_events_, "string-number-event"); SCM fingers = articulation_list (note_events_, fingering_events_, "fingering-event"); fret_board_ = make_item ("FretBoard", note_events_[0]->self_scm ()); SCM fret_notes = to_scm_list (note_events_); SCM proc = get_property (this, "noteToFretFunction"); if (ly_is_procedure (proc)) scm_call_4 (proc, context ()->self_scm (), fret_notes, scm_list_2 (tab_strings, fingers), fret_board_->self_scm ()); SCM changes = get_property (this, "chordChanges"); SCM placements = get_property (fret_board_, "dot-placement-list"); if (from_scm (changes) && ly_is_equal (last_placements_, placements)) set_property (fret_board_, "begin-of-line-visible", SCM_BOOL_T); last_placements_ = placements; } void Fretboard_engraver::stop_translation_timestep () { fret_board_ = 0; note_events_.clear (); tabstring_events_.clear (); fingering_events_.clear (); } void Fretboard_engraver::boot () { ADD_LISTENER (Fretboard_engraver, note); ADD_LISTENER (Fretboard_engraver, string_number); ADD_LISTENER (Fretboard_engraver, fingering); } ADD_TRANSLATOR (Fretboard_engraver, /* doc */ "Generate fret diagram from one or more events of type" " @code{NoteEvent}.", /* create */ "FretBoard ", /* read */ "chordChanges " "defaultStrings " "highStringOne " "maximumFretStretch " "minimumFret " "noteToFretFunction " "predefinedDiagramTable " "stringTunings " "tablatureFormat ", /* write */ "" );