From 93765e060b80897cddf1d90c7fc29aff6cdcfc4e Mon Sep 17 00:00:00 2001 From: fred Date: Tue, 26 Mar 2002 21:45:08 +0000 Subject: [PATCH] lilypond-1.1.13 --- Documentation/tex/engraving.bib | 12 ++- TODO | 11 ++- init/chord-modifiers.ly | 15 ++++ init/declarations.ly | 1 + init/nederlands.ly | 1 + input/test/c.ly | 51 ++++++++++++ input/test/chords.ly | 29 +++++++ input/twinkle-pop.ly | 38 ++++++--- lily/chord-name-engraver.cc | 137 ++++++++++++++++++++++++++++++++ lily/include/musical-pitch.hh | 7 +- lily/include/my-lily-lexer.hh | 11 ++- lily/include/my-lily-parser.hh | 46 ++++++----- lily/lexer.ll | 73 ++++++++++++----- lily/musical-pitch.cc | 16 ++-- lily/my-lily-lexer.cc | 32 ++++++-- lily/my-lily-parser.cc | 135 +++++++++++++++++++++++++++++-- lily/parser.yy | 106 +++++++++++++++++++++--- 17 files changed, 623 insertions(+), 98 deletions(-) create mode 100644 init/chord-modifiers.ly create mode 100644 input/test/c.ly create mode 100644 input/test/chords.ly create mode 100644 lily/chord-name-engraver.cc diff --git a/Documentation/tex/engraving.bib b/Documentation/tex/engraving.bib index a234775e2e..560647d93b 100644 --- a/Documentation/tex/engraving.bib +++ b/Documentation/tex/engraving.bib @@ -29,7 +29,17 @@ } - +@Book{banter, + author = {Harald Banter}, + title = {Akkord Lexikon}, + publisher = {Schott's S\"ohne}, + year = {1987}, + isbn = {ISBN 3-7957-2095-8}, + note = {Comprehensive overview of commonly used + chords. Suggests (and uses) a unification for all different kinds + of chord names.}, + address = {Mainz, Germany}, +} @Book {read78, diff --git a/TODO b/TODO index 587a96c2e5..dc35057fb1 100644 --- a/TODO +++ b/TODO @@ -21,7 +21,6 @@ BUGS: * who is trying to print too (small/big) piano braces all the time? warning: piano brace too small (16.000pt) - * latex bla.tex broken (titles / \lilyfooter stuff?) * msgfmt -o check? @@ -44,7 +43,7 @@ BUGS: * space after bars? - * [/3 c8 c16 c c c]/1 + * \type Voice \times 2/3 { [c8 c16 c16 c16 c16] } * fix singleStaffBracket @@ -52,7 +51,7 @@ BUGS: * The time signature warnings still remain, will be fixed later. -ii Summary of minor spelling irregularities: + Summary of minor spelling irregularities: - capitalization/use of underscores in property names * fix SkipBars -> skipBars @@ -92,9 +91,7 @@ STUFF * typo checks on property names? - * make engraver hacking robust. - - * --safe: disallow backslashes, disallow \include. + * --safe: disallow backslashes * use streambufs and iostream to provide IO handling for TeX stream, mudela stream, data-file. @@ -325,6 +322,8 @@ ydirection and hshift preset 3RD PARTY BUGS: + * make GCC warn about ctor that leaves member vars uninitialised. + * redhat (v?) graphical install bomb-out? * GNU diff 2.7: diff -rN does not see a new directory with empty file diff --git a/init/chord-modifiers.ly b/init/chord-modifiers.ly new file mode 100644 index 0000000000..48cc2f09f4 --- /dev/null +++ b/init/chord-modifiers.ly @@ -0,0 +1,15 @@ +%{ + chord modifiers +%} + +\chordmodifiers { + m = \musicalpitch { 0 2 -1 } + min = \musicalpitch { 0 2 -1 } + aug = \musicalpitch { 0 4 1 } + dim = \musicalpitch { 0 4 -1 } + % urg, not actually a chord-modifier, but it works + % c7 -> , c 7+ -> c b + maj = \musicalpitch { 0 6 1 } + % sus4 should delete 2 too... + sus = \musicalpitch { 0 3 0 } +} diff --git a/init/declarations.ly b/init/declarations.ly index 15573483f7..69b33ac2ce 100644 --- a/init/declarations.ly +++ b/init/declarations.ly @@ -5,6 +5,7 @@ longa = \duration { -2 0 } \include "dynamic.ly" \include "nederlands.ly" % dutch +\include "chord-modifiers.ly" \include "script.ly" diff --git a/init/nederlands.ly b/init/nederlands.ly index 35b568d30e..9b652a6bd2 100644 --- a/init/nederlands.ly +++ b/init/nederlands.ly @@ -97,3 +97,4 @@ } + diff --git a/input/test/c.ly b/input/test/c.ly new file mode 100644 index 0000000000..a2259fae93 --- /dev/null +++ b/input/test/c.ly @@ -0,0 +1,51 @@ +\version "1.0.12"; + +%{ +Would this be acceptable/good enough/convenient for entry? + + Convention/Standard Lily + + C# cis + Cb ces + Cm; Cmin c3-; c m; c min + Caug c5+; c aug; + Cdim c5-; c dim + Cmaj7 c7+; c maj + C7 c7 + Csus; Csus4 c4; c sus +%} + +scales = \notes\transpose c''\chords{ + + @1c m @c min @4c dim @c aug @c sus @c maj + @1c6 @4c7 @c9 @c11 @c13 + @1c @g @d @a @e @b @fis + @1c @f @bes @es @as @des @ges + } + +keys = \notes{ + s1 + s1 s1 s1 + s1 s1 + s1 + \key g; s1 + \key d; s1 + \key a; s1 + \key e; s1 + \key b; s1 + \key fis; s1 + \key c; s1 + \key f; s1 + \key bes; s1 + \key es; s1 + \key as; s1 + \key des; s1 + \key ges; s1 + } + +\score{ + < + \type ChordNames \scales + \type Staff < \scales \keys > + > +} diff --git a/input/test/chords.ly b/input/test/chords.ly new file mode 100644 index 0000000000..e3c0c4d182 --- /dev/null +++ b/input/test/chords.ly @@ -0,0 +1,29 @@ +\version "1.0.12"; + +%{ +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 + > +} diff --git a/input/twinkle-pop.ly b/input/twinkle-pop.ly index 1e95a8d65f..0f3ef80c6f 100644 --- a/input/twinkle-pop.ly +++ b/input/twinkle-pop.ly @@ -1,9 +1,8 @@ \header{ -filename = "twinkle.ly"; +filename = "twinkle-pop.ly"; title = "Ah, vous dirais-je, maman "; description = "twinkle twinkle in pop-song-settings"; composer = "traditional"; - enteredby = "HWN, chords by Johan Vromans"; copyright = "public domain"; } @@ -14,16 +13,28 @@ Tested Features lyrics and chords \version "1.0.10"; -melodie = \notes\relative c { - \clef"violin"; +melodie = \notes\relative c'' { + \clef "violin"; \time 2/4 ; - c''4^"C" c | g' g | a^"F" a | g2^"C" | - f4^"F" f | e^"C" e | d^"G7" d | c2^"C" | - g'4^"G" g | f^"F" f | e^"C" e | d^"G7" d | - g^"G" g | f^"F" f | e^"C" e | d^"G7" d | - c4^"C" c | g' g | a^"F" a | g2^"C" | - f4^"F" f | e^"C" e | d^"G7" d | c2^"C" | + c4 c | g' g | a a | g2 | + f4 f | e e | d d | c2 | + g'4 g | f f | e e | d d | + g g | f f | e e | d d | + % copy 1-8 + c4 c | g' g | a a | g2 | + f4 f | e e | d d | c2 | +} + +acc = \chords { + % why don't \skip, s4 work? + @2c @c @f @c + @f @c @g7 @c + @g @f @c @g7 % urg, bug! + @g @f @c @g7 + % copy 1-8 + @2c @c @f @c + @f @c @g7 @c } text = \lyrics{ @@ -39,8 +50,11 @@ text = \lyrics{ } \score { - < \notes \type Staff \melodie - \lyrics \type Lyrics \text + < + \chords \type ChordNames \acc +% \notes \type Staff=chords \acc + \notes \type Staff=melody \melodie + \lyrics \type Lyrics \text > \paper { } } diff --git a/lily/chord-name-engraver.cc b/lily/chord-name-engraver.cc new file mode 100644 index 0000000000..7bf7c05142 --- /dev/null +++ b/lily/chord-name-engraver.cc @@ -0,0 +1,137 @@ +/* + chord-name-engraver.cc -- implement Chord_name_engraver + + source file of the GNU LilyPond music typesetter + + (c) 1998 Jan Nieuwenhuizen +*/ + +#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 (i.req_l_)) + pitch_arr_.push (n->pitch_); +} + +bool +Chord_name_engraver::do_try_music (Music* m) +{ + if (Note_req* n = dynamic_cast (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; + + /* + Banter style chord names (almost). + TODO: + - don't print inclusive scale (i.e. no "9" in c 9/11) + - handle c7 / cmaj7 + - use #,b iso -es -is on tonica + - switch on property, add american (?) chordNameStyle + + Scalar chordNameStyle = get_property ("chordNameStyle"); + if (chordNameStyle == "Banner") + chord = pitches_to_banner (pitch_arr_.size ()); + + */ + + 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]; + + Array scale; + scale.push (Musical_pitch (0)); // c + scale.push (Musical_pitch (1)); // d + scale.push (Musical_pitch (2)); // e + scale.push (Musical_pitch (3)); // f + scale.push (Musical_pitch (4)); // g + scale.push (Musical_pitch (5)); // a + // 7 always means 7-... + scale.push (Musical_pitch (6, -1)); // b + + for (int i = 0; i < scale.size (); i++) + scale[i].transpose (tonic); + + //urg, should do translation in scheme. + char const *acc[] = {"\\textflat\\textflat", "\\textflat", "", "\\textsharp" , "\\textsharp\\textsharp"}; + String tonic_str = tonic.str (); + tonic_str = tonic_str.left_str (1).upper_str () + + acc[tonic.accidental_i_ + 2]; + + String add_str; + String sep_str; + for (int i=1; i < pitch_arr_.size (); i++) + { + Musical_pitch p = pitch_arr_[i]; + int trap = p.notename_i_ - tonic.notename_i_ + + (p.octave_i_ - tonic.octave_i_) * 7 + 1; + int accidental = p.accidental_i_ - scale[(trap - 1) % 7].accidental_i_; + if ((trap == 3) && (accidental == -1)) + tonic_str += "m"; // hmm + else if (accidental || (!(trap % 2) || ((i + 1 == pitch_arr_.size ()) && (trap > 5)))) + { + add_str += sep_str; + if ((trap == 7) && (accidental == 1)) + add_str += "maj7"; + else + { + add_str += to_str (trap); + if (accidental) + add_str += accidental < 0 ? "-" : "+"; + } + sep_str = "/"; + } + } + + text_p->text_str_ = tonic_str + "$^{" + add_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 (); +} + diff --git a/lily/include/musical-pitch.hh b/lily/include/musical-pitch.hh index a46471fd61..7a5fd5b5b1 100644 --- a/lily/include/musical-pitch.hh +++ b/lily/include/musical-pitch.hh @@ -21,18 +21,17 @@ */ struct Musical_pitch : public Input { - Musical_pitch (); + Musical_pitch (int notename=0, int accidental=0, int octave=0, bool cautionary=false); /// 0 is c, 6 is b int notename_i_; - /// 0 is central c - int octave_i_; /// 0 natural, 1 sharp, etc int accidental_i_; + /// 0 is central c + int octave_i_; /// Used for cautionary accidentals bool cautionary_b_; - void init () ; Musical_pitch to_relative_octave (Musical_pitch); void transpose (Musical_pitch); static int compare (Musical_pitch const&,Musical_pitch const&); diff --git a/lily/include/my-lily-lexer.hh b/lily/include/my-lily-lexer.hh index 3030a09eb4..70dc4623c8 100644 --- a/lily/include/my-lily-lexer.hh +++ b/lily/include/my-lily-lexer.hh @@ -37,19 +37,25 @@ public: String main_input_str_; void * lexval_l; Scope * toplevel_scope_p_; + bool main_input_b_; Notename_table *note_tab_p_; Array scope_l_arr_; Keyword_table * keytable_p_; int errorlevel_i_; - - + Notename_table *chordmodifier_tab_p_; + Musical_pitch lookup_notename (String s); void start_main_input (); void set_notename_table(Notename_table*tab_p); + bool chordmodifier_b (String) const; + void set_chordmodifier_table (Notename_table*tab_p); + Musical_pitch lookup_chordmodifier (String s); + bool notename_b(String) const; 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 *); @@ -60,6 +66,7 @@ public: 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; }; diff --git a/lily/include/my-lily-parser.hh b/lily/include/my-lily-parser.hh index 4e82dc909e..1c40332452 100644 --- a/lily/include/my-lily-parser.hh +++ b/lily/include/my-lily-parser.hh @@ -19,21 +19,15 @@ #include "array.hh" #include "input.hh" -class My_lily_parser { - char const* here_ch_C() const; - Array define_spot_array_; - String init_str_; - - void add_requests (Simultaneous_music*v); +class My_lily_parser +{ +public: + My_lily_parser (Sources * sources_l); + ~My_lily_parser(); - Simultaneous_music * get_note_element (Note_req * ,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); - String notename_str (Melodic_req* melodic); - void set_last_duration (Duration const *); - void set_abbrev_beam (int type_i); - friend int yyparse (void*); + void do_init_file(); + void parse_file ( String init_str, String file_str); + void set_version_check (bool ignore); public: int abbrev_beam_type_i_; @@ -53,7 +47,6 @@ public: My_lily_lexer * lexer_p_; Moment plet_mom(); - void add_notename (String, Musical_pitch req_p); Input here_input() const; void remember_spot(); Input pop_spot(); @@ -68,12 +61,23 @@ public: void set_debug(); void set_yydebug (bool); bool ignore_version_b_; -public: - void do_init_file(); - void parse_file ( String init_str, String file_str); - My_lily_parser (Sources * sources_l); - ~My_lily_parser(); - void set_version_check (bool ignore); + +private: + char const* here_ch_C() const; + Array define_spot_array_; + String init_str_; + + void add_requests (Simultaneous_music*v); + + Simultaneous_music * get_note_element (Note_req * ,Duration *); + Simultaneous_music * get_chord (Musical_pitch, Array*, Array*, 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); + String notename_str (Melodic_req* melodic); + void set_last_duration (Duration const *); + void set_abbrev_beam (int type_i); + friend int yyparse (void*); }; #endif // MY_LILY_PARSER_HH diff --git a/lily/lexer.ll b/lily/lexer.ll index 551cf48aec..3d2a87f601 100644 --- a/lily/lexer.ll +++ b/lily/lexer.ll @@ -62,6 +62,7 @@ LYRICS ({AA}|{TEX})[^0-9 \t\n\f]* %option never-interactive %option warn +%x chords %x incl %x lyrics %x notes @@ -102,7 +103,7 @@ EXTENDER [_][_] // windows-suck-suck-suck } -{ +{ "%{" { yy_push_state (longcomment); } @@ -136,11 +137,17 @@ EXTENDER [_][_] } -\\maininput { - start_main_input (); +\\maininput { + if (!main_input_b_) + { + start_main_input (); + main_input_b_ = true; + } + else + error ("\\maininput disallowed outside init files."); } -\\include { +\\include { yy_push_state (incl); } \"[^"]*\";? { /* got the include file name */ @@ -184,29 +191,27 @@ EXTENDER [_][_] R { return MEASURES; } -\\\${BLACK}*{WHITE} { +\\\${BLACK}*{WHITE} { String s=YYText () + 2; s=s.left_str (s.length_i () - 1); return scan_escaped_word (s); } -\${BLACK}*{WHITE} { +\${BLACK}*{WHITE} { String s=YYText () + 1; s=s.left_str (s.length_i () - 1); return scan_bare_word (s); } -\\\${BLACK}* { // backup rule +\\\${BLACK}* { // backup rule cerr << _ ("white expected") << endl; exit (1); } -\${BLACK}* { // backup rule +\${BLACK}* { // backup rule cerr << _ ("white expected") << endl; exit (1); } { - {ALPHAWORD} { return scan_bare_word (YYText ()); - } {NOTECOMMAND} { @@ -249,7 +254,6 @@ EXTENDER [_][_] } { - \" { start_quote (); } @@ -281,6 +285,21 @@ EXTENDER [_][_] return yylval.c = YYText ()[0]; } } +{ + {ALPHAWORD} { + return scan_bare_word (YYText ()); + } + {NOTECOMMAND} { + return scan_escaped_word (YYText () + 1); + } + {UNSIGNED} { + yylval.i = String_convert::dec2_i (String (YYText ())); + return UNSIGNED; + } + . { + return yylval.c = YYText ()[0]; + } +} <> { DOUT << "<>"; @@ -363,11 +382,18 @@ My_lily_lexer::push_note_state () 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 () { @@ -389,14 +415,13 @@ My_lily_lexer::scan_escaped_word (String str) yylval.id = id; return id->token_code_i_; } - if (YYSTATE != notes) { - if (notename_b (str)) - { - yylval.pitch = new Musical_pitch (lookup_pitch (str)); + if ((YYSTATE != notes) && (YYSTATE != chords)) { + if (notename_b (str)) { + yylval.pitch = new Musical_pitch (lookup_notename (str)); yylval.pitch->set_spot (Input (source_file_l (), here_ch_C ())); return NOTENAME_PITCH; - } + } } if (check_debug) print_declarations (true); @@ -412,13 +437,19 @@ int 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)); + yylval.pitch = new Musical_pitch (lookup_notename (str)); yylval.pitch->set_spot (Input (source_file_l (), here_ch_C ())); return NOTENAME_PITCH; + } else if (chordmodifier_b (str)) { + DOUT << "(chordmodifier)\n"; + yylval.pitch = new Musical_pitch (lookup_chordmodifier (str)); + yylval.pitch->set_spot (Input (source_file_l (), + here_ch_C ())); + return CHORDMODIFIER_PITCH; } } @@ -432,6 +463,12 @@ My_lily_lexer::note_state_b () const return YY_START == notes; } +bool +My_lily_lexer::chord_state_b () const +{ + return YY_START == chords; +} + bool My_lily_lexer::lyric_state_b () const { diff --git a/lily/musical-pitch.cc b/lily/musical-pitch.cc index 9603e025d9..f3dde21fce 100644 --- a/lily/musical-pitch.cc +++ b/lily/musical-pitch.cc @@ -10,18 +10,12 @@ #include "debug.hh" #include "main.hh" -Musical_pitch::Musical_pitch () +Musical_pitch::Musical_pitch (int n, int a, int o, bool c) { - init (); -} - -void -Musical_pitch::init () -{ - notename_i_ = 0; - octave_i_ = 0; - accidental_i_ = 0; - cautionary_b_ = false; + notename_i_ = n; + accidental_i_ = a; + octave_i_ = o; + cautionary_b_ = c; } void diff --git a/lily/my-lily-lexer.cc b/lily/my-lily-lexer.cc index b87694b729..6446083926 100644 --- a/lily/my-lily-lexer.cc +++ b/lily/my-lily-lexer.cc @@ -28,6 +28,8 @@ static Keyword_ent the_key_tab[]={ {"alternative", ALTERNATIVE}, {"bar", BAR}, {"cadenza", CADENZA}, + {"chordmodifiers", CHORDMODIFIERS}, + {"chords", CHORDS}, {"clef", CLEF}, {"cm", CM_T}, {"consists", CONSISTS}, @@ -80,6 +82,8 @@ My_lily_lexer::My_lily_lexer() scope_l_arr_.push (toplevel_scope_p_); errorlevel_i_ = 0; note_tab_p_ = new Notename_table; + chordmodifier_tab_p_ = new Notename_table; + main_input_b_ = false; } int @@ -105,7 +109,10 @@ My_lily_lexer::start_main_input () if (!monitor->silent_b ("InitLexer") && check_debug) set_debug (1); + new_input (main_input_str_, source_global_l); + if (safe_global_b) + allow_includes_b_ = false; print_declarations(true); } @@ -167,11 +174,17 @@ My_lily_lexer::LexerError (char const *s) } Musical_pitch -My_lily_lexer::lookup_pitch (String s) +My_lily_lexer::lookup_notename (String s) { return (*note_tab_p_)[s]; } +Musical_pitch +My_lily_lexer::lookup_chordmodifier (String s) +{ + return (*chordmodifier_tab_p_)[s]; +} + bool My_lily_lexer::notename_b (String s) const { @@ -179,16 +192,23 @@ My_lily_lexer::notename_b (String s) const } void -My_lily_lexer::add_notename (String s, Musical_pitch p) +My_lily_lexer::set_notename_table (Notename_table *p) { - (*note_tab_p_)[s] = p; + delete note_tab_p_; + note_tab_p_ = p; +} + +bool +My_lily_lexer::chordmodifier_b (String s) const +{ + return chordmodifier_tab_p_->elem_b (s); } void -My_lily_lexer::set_notename_table(Notename_table *p) +My_lily_lexer::set_chordmodifier_table (Notename_table *p) { - delete note_tab_p_; - note_tab_p_ = p; + delete chordmodifier_tab_p_; + chordmodifier_tab_p_ = p; } char diff --git a/lily/my-lily-parser.cc b/lily/my-lily-parser.cc index 86270bf7c3..75ff14f5c7 100644 --- a/lily/my-lily-parser.cc +++ b/lily/my-lily-parser.cc @@ -4,6 +4,7 @@ source file of the GNU LilyPond music typesetter (c) 1997--1998 Han-Wen Nienhuys + Jan Nieuwenhuizen */ #include "my-lily-parser.hh" @@ -157,6 +158,133 @@ My_lily_parser::get_rest_element (String s, Duration * duration_p) return velt_p; } +Simultaneous_music * +My_lily_parser::get_chord (Musical_pitch tonic, Array* add_arr_p, Array* 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; + Musical_pitch q = (*add_arr_p)[i]; + // duh, c7 should mean + if (q.notename_i_ == 6) + q.accidental_i_--; + p.transpose (q); + (*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; + Musical_pitch q = (*add_arr_p)[i]; + // duh, c7 should mean + if (q.notename_i_ == 6) + q.accidental_i_--; + p.transpose (q); + (*sub_arr_p)[i] = p; + } + sub_arr_p->sort (Musical_pitch::compare); + + Musical_pitch third (2); + Musical_pitch mthird (2, -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->push (p); + else if ((add_arr_p->top () < p) && (add_arr_p->top ().notename_i_ != p.notename_i_)) + add_arr_p->push (p); + add_arr_p->sort (Musical_pitch::compare); + + Array triads; + triads.push (third); // c e + triads.push (mthird); // d f + triads.push (mthird); // e g + triads.push (third); // f a + // 7 always seems means 7-... + triads.push (third); // g b +// triads.push (mthird); // g bes + triads.push (mthird); // a c + triads.push (mthird); // b d + + /* + if first addition is 4, assume sus4 and don't add third implicitely + */ + Musical_pitch sus (3); + sus.transpose (tonic); + if (add_arr_p->size ()) + if ((*add_arr_p)[0] == sus) + missing.transpose (mthird); + + /* + add missing triads + */ + for (int i = 0; i < add_arr_p->size (); i++) + { + Musical_pitch p = (*add_arr_p)[i]; + if (p > missing) + while (p > missing) + { + if (p.notename_i_ != missing.notename_i_) + { + if ((missing.notename_i_ - tonic.notename_i_ + 7) % 7 == 6) + { + Musical_pitch special_seven = missing; + Musical_pitch lower (0, -1); + special_seven.transpose (lower); + add_arr_p->insert (special_seven, i++); + } + else + add_arr_p->insert (missing, i++); + } + missing.transpose (triads[(missing.notename_i_ - tonic.notename_i_ + 7) % 7]); + } + 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) { @@ -308,13 +436,6 @@ My_lily_parser::here_input() const return Input (f_l, here_ch_C()); } -void -My_lily_parser::add_notename (String s, Musical_pitch p) -{ - lexer_p_->add_notename (s, p); - -} - Paper_def* My_lily_parser::default_paper_p () { diff --git a/lily/parser.yy b/lily/parser.yy index b2b807ac8f..2cf38355e3 100644 --- a/lily/parser.yy +++ b/lily/parser.yy @@ -47,7 +47,7 @@ // mmm Mudela_version oldest_version ("1.0.7"); -Mudela_version version ("1.0.11"); +Mudela_version version ("1.0.12"); // needed for bison.simple's malloc() and free() @@ -104,11 +104,12 @@ Paper_def* current_paper = 0; Array *pitch_arr; Array * strvec; Array *intvec; + Atom * symbol; Box *box; - Simultaneous_music *chord; + Notename_table *chordmodifiertab; Duration *duration; + General_script_def * script; Identifier *id; - Translator* trans; Music *music; Music_list *music_list; Score *score; @@ -124,14 +125,14 @@ Paper_def* current_paper = 0; Paper_def *paper; Real real; Request * request; - General_script_def * script; Scalar *scalar; + Simultaneous_music *chord; String *string; - Atom * symbol; Symtable * symtable; Symtables* symtables; - Text_def * textdef; Tempo_req *tempo; + Text_def * textdef; + Translator* trans; char c; const char *consstr; int i; @@ -163,6 +164,8 @@ yylex (YYSTYPE *s, void * v_l) %token BAR %token BEAMPLET %token CADENZA +%token CHORDMODIFIERS +%token CHORDS %token CLEF %token CM_T %token CONSISTS @@ -220,6 +223,7 @@ yylex (YYSTYPE *s, void * v_l) %type dots %token DIGIT %token NOTENAME_PITCH +%token CHORDMODIFIER_PITCH %token DURATION_IDENTIFIER %token IDENTIFIER %token NOTENAME_TABLE_IDENTIFIER @@ -264,6 +268,9 @@ yylex (YYSTYPE *s, void * v_l) %type explicit_musical_pitch steno_musical_pitch musical_pitch absolute_musical_pitch %type steno_notepitch %type pitch_list +%type chord +%type chord_additions chord_subtractions +%type chord_note %type midi_block midi_body %type duration_length @@ -288,8 +295,9 @@ yylex (YYSTYPE *s, void * v_l) %type symtable symtable_body %type translator_spec translator_spec_body %type tempo_request -%type notenames_body notenames_block -%expect 4 +%type notenames_body notenames_block chordmodifiers_block + +%expect 6 %left '-' '+' @@ -309,6 +317,9 @@ toplevel_expression: notenames_block { THIS->lexer_p_->set_notename_table ($1); } + | chordmodifiers_block { + THIS->lexer_p_->set_chordmodifier_table ($1); + } | mudela_header { delete header_global_p; header_global_p = $1; @@ -355,6 +366,11 @@ check_version: ; +chordmodifiers_block: + CHORDMODIFIERS '{' notenames_body '}' { $$ = $3; } + ; + + notenames_block: NOTENAMES '{' notenames_body '}' { $$ = $3; } ; @@ -421,6 +437,9 @@ block_identifier: $$ = new Score_identifier ($1, SCORE_IDENTIFIER); } + | chordmodifiers_block { + $$ = new Notename_table_identifier ($1, NOTENAME_TABLE_IDENTIFIER); + } | notenames_block { $$ = new Notename_table_identifier ($1, NOTENAME_TABLE_IDENTIFIER); } @@ -807,7 +826,13 @@ Composite_music: { $$ = $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 @@ -1400,7 +1425,8 @@ abbrev_type: 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); @@ -1425,8 +1451,68 @@ simple_element: $$ = 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: + notemode_duration steno_musical_pitch chord_additions chord_subtractions { + $$ = THIS->get_chord (*$2, $3, $4, *$1); + }; + +chord_additions: + { + $$ = new Array; + } + | chord_additions chord_note { + $1->push (*$2); + $$ = $1; + } + | chord_additions CHORDMODIFIER_PITCH { + /* + urg, this is kind of ugly. + all but "sus" chord modifiers can be + handled as chord_additions... + */ + $1->push (*$2); + $$ = $1; + } ; +chord_note: + UNSIGNED { + $$ = new Musical_pitch; + $$->notename_i_ = ($1 - 1) % 7; + $$->octave_i_ = $1 > 7 ? 1 : 0; + $$->accidental_i_ = 0; + } + | UNSIGNED '+' { + $$ = new Musical_pitch; + $$->notename_i_ = ($1 - 1) % 7; + $$->octave_i_ = $1 > 7 ? 1 : 0; + $$->accidental_i_ = 1; + } + | UNSIGNED '-' { + $$ = new Musical_pitch; + $$->notename_i_ = ($1 - 1) % 7; + $$->octave_i_ = $1 > 7 ? 1 : 0; + $$->accidental_i_ = -1; + } + ; + +chord_subtractions: + { + $$ = new Array; + } + | '^' chord_subtractions chord_note { + $2->push (*$3); + $$ = $2; + } + ; /* UTILITIES -- 2.39.5