+pl 10.jcn1
+ - input/test/chords.ly
+ - \type ChordNames and chord-name-engraver.*
+ - chords mode: \chords { <c e g> @c; @d7; }
+
pl 10
pl 9.jcn3
MAJOR_VERSION=1
MINOR_VERSION=1
PATCH_LEVEL=10
-MY_PATCH_LEVEL=
+MY_PATCH_LEVEL=jcn1
# use the above to send patches: MY_PATCH_LEVEL is always empty for a
# released version.
\accepts "RhythmicStaff";
\accepts "GrandStaff";
\accepts "Lyrics";
+ \accepts "ChordNames";
}
\accepts "RhythmicStaff";
\accepts "GrandStaff";
\accepts "Lyrics";
+ \accepts "ChordNames";
}
\translator{
\accepts "LyricVoice";
}
+\translator{
+ \type "Line_group_engraver_group";
+
+ \name ChordNameVoice ;
+ \consists "Separating_line_group_engraver";
+ \consists "Chord_name_engraver";
+}
+
+\translator {
+ \type "Line_group_engraver_group";
+ \name ChordNames;
+ \consists "Vertical_align_engraver";
+ \accepts "ChordNameVoice";
+}
+
ScoreContext = \translator {
\type Score_engraver;
\name Score;
\accepts "Staff";
\accepts "RhythmicStaff";
\accepts "Lyrics";
+ \accepts "ChordNames";
\accepts "GrandStaff";
\accepts "ChoirStaff";
};
\accepts "Staff";
\accepts "RhythmicStaff";
\accepts "Lyrics";
+ \accepts "ChordNames";
\accepts "GrandStaff";
};
--- /dev/null
+%{
+Would this be acceptable/good enough/convenient for entry?
+
+ Convention/Standard Logical/Lily(?)
+
+ C# cis
+ Cb ces
+ Cm/Cmin c3-
+ Caug c5+
+ Cdim c5-
+ Cmaj7 c7
+ C7 c7-
+ Csus/Csus4 c4^3
+%}
+
+scales = \notes\transpose c''\chords{
+ @c; @g; @d; @a; @e; @b; @fis;
+ @c; @f; @bes; @es; @as; @des; @ges;
+ @c6; @c7; @c9; @c11; @c13;
+ }
+
+\score{
+ <
+ \type ChordNames \scales
+ \type Staff \scales
+ >
+}
--- /dev/null
+/*
+ chord-name-engraver.cc -- implement Chord_name_engraver
+
+ source file of the GNU LilyPond music typesetter
+
+ (c) 1998 Jan Nieuwenhuizen <janneke@gnu.org>
+*/
+
+#include "chord-name-engraver.hh"
+#include "musical-request.hh"
+#include "text-item.hh"
+#include "paper-def.hh"
+#include "lookup.hh"
+#include "paper-def.hh"
+#include "main.hh"
+#include "dimensions.hh"
+
+ADD_THIS_TRANSLATOR (Chord_name_engraver);
+
+Chord_name_engraver::Chord_name_engraver ()
+{
+}
+
+void
+Chord_name_engraver::acknowledge_element (Score_element_info i)
+{
+ if (Note_req* n = dynamic_cast<Note_req*> (i.req_l_))
+ pitch_arr_.push (n->pitch_);
+}
+
+bool
+Chord_name_engraver::do_try_music (Music* m)
+{
+ if (Note_req* n = dynamic_cast<Note_req*> (m))
+ {
+ pitch_arr_.push (n->pitch_);
+ return true;
+ }
+ return false;
+}
+
+void
+Chord_name_engraver::do_process_requests ()
+{
+ if (text_p_arr_.size ())
+ return;
+ if (!pitch_arr_.size ())
+ return;
+
+ Scalar style = get_property ("textstyle");
+ Scalar alignment = get_property ("textalignment");
+ Text_def* text_p = new Text_def;
+ text_p->align_dir_ = LEFT;
+ if (style.length_i ())
+ text_p->style_str_ = style;
+ if (alignment.isnum_b())
+ text_p->align_dir_= (Direction)(int)alignment;
+
+ Musical_pitch tonic = pitch_arr_[0];
+ text_p->text_str_ = tonic.str ();
+ for (int i=1; i < pitch_arr_.size (); i++)
+ {
+ Musical_pitch p = pitch_arr_[i];
+ int trap = (p.notename_i_ - tonic.notename_i_ + 8) % 8 + 1;
+ if (((trap != 3) && (trap != 5)) || (p.accidental_i_))
+ {
+ text_p->text_str_ += to_str ((p.notename_i_ - tonic.notename_i_ + 8) % 8 + 1);
+ if (p.accidental_i_)
+ text_p->text_str_ += p.accidental_i_ < 0 ? "-" : "+";
+ if (i + 1 < pitch_arr_.size ())
+ text_p->text_str_ += "/";
+ }
+ }
+
+ Text_item* item_p = new Text_item (text_p);
+ item_p->dir_ = DOWN;
+ item_p->fat_b_ = true;
+ text_p_arr_.push (item_p);
+ announce_element (Score_element_info (item_p, 0));
+}
+
+void
+Chord_name_engraver::do_pre_move_processing ()
+{
+ for (int i=0; i < text_p_arr_.size (); i++)
+ {
+ typeset_element (text_p_arr_[i]);
+ }
+ text_p_arr_.clear ();
+ pitch_arr_.clear ();
+}
+
--- /dev/null
+/*
+ chord-name-engraver.hh -- declare Chord_name_engraver
+
+ source file of the GNU LilyPond music typesetter
+
+ (c) 1998 Jan Nieuwenhuizen <janneke@gnu.org>
+*/
+
+#ifndef CHORD_NAME_ENGRAVER_HH
+#define CHORD_NAME_ENGRAVER_HH
+
+#include "engraver.hh"
+#include "array.hh"
+#include "musical-pitch.hh"
+
+#include "lily-proto.hh"
+
+class Chord_name_engraver : public Engraver
+{
+protected:
+ virtual void do_pre_move_processing ();
+ virtual void acknowledge_element (Score_element_info i);
+ virtual void do_process_requests ();
+ virtual bool do_try_music (Music* m);
+
+public:
+ Chord_name_engraver ();
+ VIRTUAL_COPY_CONS (Translator);
+
+private:
+ Array<Musical_pitch> pitch_arr_;
+ Link_array<Text_item> text_p_arr_;
+};
+
+#endif // CHORD_NAME_ENGRAVER_HH
struct Cadenza_req;
struct Change_iterator;
struct Change_translator;
-struct Simultaneous_music;
+struct Chord_name_engraver;
struct Clef_change_req;
struct Clef_item;
struct Clef_engraver;
struct Rhythmic_head;
struct Rhythmic_grouping_req;
struct Rhythmic_req;
-struct Single_malt_grouping_item;
struct Scope;
struct Separating_group_spanner;
struct Score;
struct Script_engraver;
struct Script_req;
struct Simple_music;
+struct Simultaneous_music;
+struct Single_malt_grouping_item;
struct Skip_req;
struct Slur;
struct Slur_engraver;
virtual void do_pre_move_processing();
virtual bool do_try_music (Music*);
virtual void do_process_requests();
- virtual void do_post_move_processing();
public:
Lyric_engraver();
Identifier*lookup_identifier (String s);
Musical_pitch lookup_pitch (String s);
void push_note_state();
+ void push_chord_state();
void push_lyric_state();
void pop_state();
void LexerError (char const *);
void print_declarations (bool init_b) const;
void add_notename (String, Musical_pitch);
bool note_state_b() const;
+ bool chord_state_b() const;
bool lyric_state_b() const;
};
void add_requests (Simultaneous_music*v);
Simultaneous_music * get_note_element (Note_req * ,Duration *);
+ Simultaneous_music * get_chord (Musical_pitch, Array<Musical_pitch>*, Array<Musical_pitch>*, Duration);
Simultaneous_music* get_rest_element (String, Duration *);
Simultaneous_music* get_word_element (String, Duration*);
Melodic_req* get_melodic_req (Melodic_req* melodic, int quotes);
%option never-interactive
%option warn
+%x chords
%x incl
%x lyrics
%x notes
// windows-suck-suck-suck
}
-<notes,incl,INITIAL,lyrics>{
+<INITIAL,chords,incl,lyrics,notes>{
"%{" {
yy_push_state (longcomment);
}
}
-<notes,INITIAL,lyrics>\\maininput {
+<INITIAL,chords,lyrics,notes>\\maininput {
start_main_input ();
}
-<notes,INITIAL,lyrics>\\include {
+<INITIAL,chords,lyrics,notes>\\include {
yy_push_state (incl);
}
<incl>\"[^"]*\";? { /* got the include file name */
<notes>R {
return MEASURES;
}
-<INITIAL,lyrics,notes>\\\${BLACK}*{WHITE} {
+<INITIAL,chords,lyrics,notes>\\\${BLACK}*{WHITE} {
String s=YYText () + 2;
s=s.left_str (s.length_i () - 1);
return scan_escaped_word (s);
}
-<INITIAL,lyrics,notes>\${BLACK}*{WHITE} {
+<INITIAL,chords,lyrics,notes>\${BLACK}*{WHITE} {
String s=YYText () + 1;
s=s.left_str (s.length_i () - 1);
return scan_bare_word (s);
}
-<INITIAL,lyrics,notes>\\\${BLACK}* { // backup rule
+<INITIAL,chords,lyrics,notes>\\\${BLACK}* { // backup rule
cerr << _ ("white expected") << endl;
exit (1);
}
-<INITIAL,lyrics,notes>\${BLACK}* { // backup rule
+<INITIAL,chords,lyrics,notes>\${BLACK}* { // backup rule
cerr << _ ("white expected") << endl;
exit (1);
}
<notes>{
-
{ALPHAWORD} {
return scan_bare_word (YYText ());
-
}
{NOTECOMMAND} {
}
<lyrics>{
-
\" {
start_quote ();
}
return yylval.c = YYText ()[0];
}
}
+<chords>{
+ {ALPHAWORD} {
+ return scan_bare_word (YYText ());
+ }
+ {UNSIGNED} {
+ yylval.i = String_convert::dec2_i (String (YYText ()));
+ return UNSIGNED;
+ }
+ . {
+ return yylval.c = YYText ()[0];
+ }
+}
<<EOF>> {
DOUT << "<<eof>>";
yy_push_state (notes);
}
+void
+My_lily_lexer::push_chord_state ()
+{
+ yy_push_state (chords);
+}
+
void
My_lily_lexer::push_lyric_state ()
{
yy_push_state (lyrics);
}
+
void
My_lily_lexer::pop_state ()
{
yylval.id = id;
return id->token_code_i_;
}
- if (YYSTATE != notes) {
+ if ((YYSTATE != notes) && (YYSTATE != chords)) {
if (notename_b (str))
{
yylval.pitch = new Musical_pitch (lookup_pitch (str));
My_lily_lexer::scan_bare_word (String str)
{
DOUT << "word: `" << str<< "'\n";
- if (YYSTATE == notes){
+ if ((YYSTATE == notes) || (YYSTATE == chords)) {
if (notename_b (str)) {
DOUT << "(notename)\n";
yylval.pitch = new Musical_pitch (lookup_pitch (str));
return YY_START == notes;
}
+bool
+My_lily_lexer::chord_state_b () const
+{
+ return YY_START == chords;
+}
+
bool
My_lily_lexer::lyric_state_b () const
{
}
}
-void
-Lyric_engraver::do_post_move_processing()
-{
-}
-
void
Lyric_engraver::do_pre_move_processing()
{
{"alternative", ALTERNATIVE},
{"bar", BAR},
{"cadenza", CADENZA},
+ {"chords", CHORDS},
{"clef", CLEF},
{"cm", CM_T},
{"consists", CONSISTS},
return velt_p;
}
+Simultaneous_music *
+My_lily_parser::get_chord (Musical_pitch tonic, Array<Musical_pitch>* add_arr_p, Array<Musical_pitch>* sub_arr_p, Duration d)
+{
+ Simultaneous_music*v = new Request_chord;
+ v->set_spot (here_input ());
+
+ Note_req* n = new Note_req;
+ n->pitch_ = tonic;
+ n->duration_ = d;
+ v->add_music (n);
+
+ for (int i = 0; i < add_arr_p->size (); i++)
+ {
+ Musical_pitch p = tonic;
+ p.transpose ((*add_arr_p)[i]);
+ (*add_arr_p)[i] = p;
+ }
+ add_arr_p->sort (Musical_pitch::compare);
+ for (int i = 0; i < sub_arr_p->size (); i++)
+ {
+ Musical_pitch p = tonic;
+ p.transpose ((*sub_arr_p)[i]);
+ (*sub_arr_p)[i] = p;
+ }
+ sub_arr_p->sort (Musical_pitch::compare);
+
+ Musical_pitch third;
+ third.notename_i_ = 2;
+
+ Musical_pitch mthird;
+ mthird.notename_i_ = 2;
+ mthird.accidental_i_ = -1;
+
+ Musical_pitch missing;
+ missing = tonic;
+ missing.transpose (third);
+
+ Musical_pitch p;
+ p = tonic;
+ p.transpose (third);
+ p.transpose (mthird);
+
+ /*
+ must have minimum at 5 (3 is added automatically as missing)
+ */
+ if (!add_arr_p->size ()
+ || ((add_arr_p->size () == 1) &&
+ ((add_arr_p->top ().notename_i_ != p.notename_i_)
+ || (add_arr_p->top () < p))))
+ add_arr_p->push (p);
+
+ Array<Musical_pitch> triads;
+ triads.push (third); // c e
+ triads.push (mthird); // d f
+ triads.push (mthird); // e g
+ triads.push (third); // f a
+ triads.push (third); // g b
+ triads.push (mthird); // a c
+ triads.push (mthird); // b d
+
+ /*
+ add missing triads
+ */
+ for (int i = 0; i < add_arr_p->size (); i++)
+ {
+ Musical_pitch p = (*add_arr_p)[i];
+ if ((p > missing) && (p.notename_i_ != missing.notename_i_))
+ while ((p > missing) && (p.notename_i_ != missing.notename_i_))
+ {
+ add_arr_p->insert (missing, i++);
+ missing.transpose (triads[(missing.notename_i_ - tonic.notename_i_ + 8) % 8]);
+ }
+ else
+ i++;
+ }
+
+ /*
+ add all that aren't subtracted
+ */
+ for (int i = 0; i < add_arr_p->size (); i++)
+ {
+ Musical_pitch p = (*add_arr_p)[i];
+ Note_req* n = new Note_req;
+ n->pitch_ = p;
+ n->duration_ = d;
+ for (int j = 0; j < sub_arr_p->size (); j++)
+ {
+ if (p == (*sub_arr_p)[j])
+ {
+ delete n;
+ n = 0;
+ break;
+ }
+ }
+ if (n)
+ v->add_music (n);
+ }
+
+ v->set_spot (here_input ());
+ return v;
+}
+
Simultaneous_music *
My_lily_parser::get_note_element (Note_req *rq, Duration * duration_p)
{
%token BAR
%token BEAMPLET
%token CADENZA
+%token CHORDS
%token CLEF
%token CM_T
%token CONSISTS
%type <pitch> explicit_musical_pitch steno_musical_pitch musical_pitch absolute_musical_pitch
%type <notereq> steno_notepitch
%type <pitch_arr> pitch_list
+%type <music> chord
+%type <pitch_arr> chord_additions chord_subtractions
+%type <pitch> chord_note
%type <midi> midi_block midi_body
%type <duration> duration_length
{ $$ = $3;
THIS->lexer_p_->pop_state ();
}
-
+ | CHORDS
+ { THIS->lexer_p_->push_chord_state (); }
+ Music
+ {
+ $$ = $3;
+ THIS->lexer_p_->pop_state ();
+ }
| LYRICS
{ THIS->lexer_p_->push_lyric_state (); }
Music
simple_element:
steno_notepitch notemode_duration {
- if (!THIS->lexer_p_->note_state_b ())
+ if (!THIS->lexer_p_->note_state_b ()
+ && !THIS->lexer_p_->chord_state_b ())
THIS->parser_error (_ ("have to be in Note mode for notes"));
$1->duration_ = *$2;
$$ = THIS->get_note_element ($1, $2);
$$ = THIS->get_word_element (*$1, $2);
delete $1;
}
+ | '@' chord ';' {
+ if (!THIS->lexer_p_->chord_state_b ())
+ THIS->parser_error (_ ("have to be in Chord mode for chords"));
+ $$ = $2;
+ }
+ ;
+
+
+chord:
+ NOTENAME_PITCH chord_additions chord_subtractions {
+ Duration d;
+ d.durlog_i_ = 0;
+ $$ = THIS->get_chord (*$1, $2, $3, d);
+ };
+
+chord_additions:
+ {
+ $$ = new Array<Musical_pitch>;
+ }
+ | chord_additions chord_note {
+ $1->push (*$2);
+ $$ = $1;
+ }
;
+chord_note:
+ UNSIGNED {
+ $$ = new Musical_pitch;
+ $$->notename_i_ = ($1 - 1) % 8;
+ $$->octave_i_ = $1 > 7 ? 1 : 0;
+ $$->accidental_i_ = 0;
+ }
+ | UNSIGNED '+' {
+ $$ = new Musical_pitch;
+ $$->notename_i_ = ($1 - 1) % 8;
+ $$->octave_i_ = $1 > 7 ? 1 : 0;
+ $$->accidental_i_ = 1;
+ }
+ | UNSIGNED '-' {
+ $$ = new Musical_pitch;
+ $$->notename_i_ = ($1 - 1) % 8;
+ $$->octave_i_ = $1 > 7 ? 1 : 0;
+ $$->accidental_i_ = -1;
+ }
+ ;
+
+chord_subtractions:
+ {
+ $$ = new Array<Musical_pitch>;
+ }
+ | '^' chord_subtractions chord_note {
+ $2->push (*$3);
+ $$ = $2;
+ }
+ ;
/*
UTILITIES