]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/parser.yy
Merge branch 'jneeman' of git+ssh://jneem@git.sv.gnu.org/srv/git/lilypond into jneeman
[lilypond.git] / lily / parser.yy
index dff3ee921df7746974d42a129b52594a1ea464ed..64d6103d44d51dff51dd7900ed4100c4551802c5 100644 (file)
@@ -9,6 +9,7 @@
 
 %{
 
+#define YYDEBUG 1
 #define YYERROR_VERBOSE 1
 #define YYPARSE_PARAM my_lily_parser
 #define YYLEX_PARAM my_lily_parser
@@ -79,7 +80,6 @@ using namespace std;
 #include "lily-guile.hh"
 #include "lily-lexer.hh"
 #include "lily-parser.hh"
-#include "lilypond-input-version.hh"
 #include "main.hh"
 #include "misc.hh"
 #include "music.hh"
@@ -107,7 +107,7 @@ using namespace std;
 
 %{
 
-#define MY_MAKE_MUSIC(x)  make_music_by_name (ly_symbol2scm (x))
+#define MY_MAKE_MUSIC(x, spot)  make_music_with_input (ly_symbol2scm (x), spot)
 
 /* ES TODO:
 - Don't use lily module, create a new module instead.
@@ -131,8 +131,8 @@ SCM get_next_unique_lyrics_context_id ();
 #endif
 
 
-
-SCM make_music_relative (Pitch start, SCM music);
+static Music *make_music_with_input (SCM name, Input where);
+SCM make_music_relative (Pitch start, SCM music, Input loc);
 SCM run_music_function (Lily_parser *, SCM expr);
 SCM get_first_context_id (SCM type, Music *m);
 SCM make_chord_elements (SCM pitch, SCM dur, SCM modification_list);
@@ -156,7 +156,6 @@ void set_music_properties (Music *p, SCM a);
 /* Keyword tokens with plain escaped name.  */
 %token ACCEPTS "\\accepts"
 %token ADDLYRICS "\\addlyrics"
-%token ADDQUOTE "\\addquote"
 %token ALIAS "\\alias"
 %token ALTERNATIVE "\\alternative"
 %token BOOK "\\book"
@@ -255,6 +254,13 @@ If we give names, Bison complains.
 %token <i> E_UNSIGNED
 %token <i> UNSIGNED
 
+/* Artificial tokens, for more generic function syntax */
+%token <i> EXPECT_MARKUP;
+%token <i> EXPECT_MUSIC;
+%token <i> EXPECT_SCM;
+/* After the last argument. */
+%token <i> EXPECT_NO_MORE_ARGS;
+
 %token <scm> BOOK_IDENTIFIER
 %token <scm> CHORDMODIFIER_PITCH
 %token <scm> CHORD_MODIFIER
@@ -276,22 +282,6 @@ If we give names, Bison complains.
 %token <scm> MARKUP_HEAD_SCM0_SCM1_SCM2
 %token <scm> MARKUP_IDENTIFIER
 %token <scm> MUSIC_FUNCTION
-%token <scm> MUSIC_FUNCTION_MARKUP 
-%token <scm> MUSIC_FUNCTION_MARKUP_MARKUP 
-%token <scm> MUSIC_FUNCTION_MARKUP_MARKUP_MUSIC 
-%token <scm> MUSIC_FUNCTION_MARKUP_MUSIC 
-%token <scm> MUSIC_FUNCTION_MARKUP_MUSIC_MUSIC 
-%token <scm> MUSIC_FUNCTION_MUSIC 
-%token <scm> MUSIC_FUNCTION_MUSIC_MUSIC 
-%token <scm> MUSIC_FUNCTION_SCM 
-%token <scm> MUSIC_FUNCTION_SCM_MUSIC 
-%token <scm> MUSIC_FUNCTION_SCM_MUSIC_MUSIC 
-%token <scm> MUSIC_FUNCTION_SCM_SCM_MUSIC_MUSIC 
-%token <scm> MUSIC_FUNCTION_SCM_SCM 
-%token <scm> MUSIC_FUNCTION_SCM_SCM_MUSIC 
-%token <scm> MUSIC_FUNCTION_SCM_SCM_SCM 
-%token <scm> MUSIC_FUNCTION_SCM_SCM_SCM_MUSIC 
-%token <scm> MUSIC_FUNCTION_SCM_SCM_SCM_SCM_MUSIC 
 %token <scm> MUSIC_IDENTIFIER
 %token <scm> NOTENAME_PITCH
 %token <scm> NUMBER_IDENTIFIER
@@ -360,10 +350,6 @@ If we give names, Bison complains.
 %type <scm> absolute_pitch
 %type <scm> assignment_id
 %type <scm> bare_number
-%type <scm> music_function_event
-%type <scm> music_function_chord_body
-%type <scm> music_function_musicless_prefix
-%type <scm> music_function_musicless_function
 %type <scm> bass_figure
 %type <scm> figured_bass_modification
 %type <scm> br_bass_figure
@@ -385,6 +371,11 @@ If we give names, Bison complains.
 %type <scm> figure_spec
 %type <scm> fraction
 %type <scm> full_markup
+%type <scm> function_scm_argument
+%type <scm> function_arglist
+%type <scm> function_arglist_music_last
+%type <scm> function_arglist_nonmusic_last
+%type <scm> function_arglist_nonmusic
 %type <scm> identifier_init
 %type <scm> lilypond_header
 %type <scm> lilypond_header_body
@@ -401,6 +392,9 @@ If we give names, Bison complains.
 %type <scm> mode_changing_head
 %type <scm> mode_changing_head_with_context
 %type <scm> multiplied_duration
+%type <scm> music_function_identifier_musicless_prefix
+%type <scm> music_function_event
+%type <scm> music_function_chord_body
 %type <scm> new_chord
 %type <scm> new_lyrics
 %type <scm> number_expression
@@ -426,7 +420,6 @@ If we give names, Bison complains.
 %type <scm> step_number
 %type <scm> step_numbers 
 %type <scm> string
-%type <scm> function_scm_argument
 
 %type <score> score_block
 %type <score> score_body
@@ -830,7 +823,7 @@ music_list:
 
        }
        | music_list error {
-               Music *m = MY_MAKE_MUSIC("Music");
+               Music *m = MY_MAKE_MUSIC("Music", @$);
                // ugh. code dup 
                m->set_property ("error-found", SCM_BOOL_T);
                SCM s = $$;
@@ -924,72 +917,48 @@ function_scm_argument:
        | simple_string
        ;
 
-/*
-TODO: use code generation for this
-*/
-music_function_musicless_function:
-       MUSIC_FUNCTION {
-               $$ = scm_list_2 ($1, make_input (@$));
-       }
-       | MUSIC_FUNCTION_SCM function_scm_argument {
-               $$ = scm_list_3 ($1, make_input (@$), $2);
-       }
-       | MUSIC_FUNCTION_MARKUP full_markup {
-               $$ = scm_list_3 ($1, make_input (@$), $2);
-       }
-       | MUSIC_FUNCTION_SCM_SCM function_scm_argument function_scm_argument {
-               $$ = scm_list_4 ($1, make_input (@$), $2, $3);
-       }
-       | MUSIC_FUNCTION_SCM_SCM_SCM function_scm_argument function_scm_argument function_scm_argument {
-               $$ = scm_list_5 ($1, make_input (@$), $2, $3, $4);
-       }
-       | MUSIC_FUNCTION_MARKUP_MARKUP full_markup full_markup {
-               $$ = scm_list_4 ($1, make_input (@$), $2, $3);
+/* An argument list. If a function \foo expects scm scm music, then the lexer expands \foo into the token sequence:
+ MUSIC_FUNCTION EXPECT_MUSIC EXPECT_SCM EXPECT_SCM
+and this rule returns the reversed list of arguments. */
+
+function_arglist_music_last:
+       EXPECT_MUSIC function_arglist music {
+               $$ = scm_cons ($3, $2);
        }
        ;
 
-/*
-TODO: use code generation for this
-*/
-music_function_musicless_prefix:
-       MUSIC_FUNCTION_MUSIC {
-               $$ = scm_list_2 ($1, make_input (@$));
+function_arglist_nonmusic_last:
+       EXPECT_MARKUP function_arglist full_markup {
+               $$ = scm_cons ($3, $2);
        }
-       | MUSIC_FUNCTION_SCM_MUSIC function_scm_argument { 
-               $$ = scm_list_3 ($1, make_input (@$), $2);
+       | EXPECT_SCM function_arglist function_scm_argument {
+               $$ = scm_cons ($3, $2);
        }
-       | MUSIC_FUNCTION_SCM_SCM_MUSIC function_scm_argument function_scm_argument {
-               $$ = scm_list_4 ($1, make_input (@$), $2, $3);
+       ;
+
+function_arglist_nonmusic: EXPECT_NO_MORE_ARGS {
+               $$ = SCM_EOL;
        }
-       | MUSIC_FUNCTION_SCM_SCM_SCM_MUSIC function_scm_argument function_scm_argument function_scm_argument {
-               $$ = scm_list_5 ($1, make_input (@$), $2, $3, $4);
+       | EXPECT_MARKUP function_arglist_nonmusic full_markup {
+               $$ = scm_cons ($3, $2);
        }
-       | MUSIC_FUNCTION_SCM_SCM_SCM_SCM_MUSIC function_scm_argument function_scm_argument function_scm_argument function_scm_argument {
-               $$ = scm_list_n ($1, make_input (@$), $2, $3, $4, $5, SCM_UNDEFINED);
+       | EXPECT_SCM function_arglist_nonmusic function_scm_argument {
+               $$ = scm_cons ($3, $2);
        }
-       | MUSIC_FUNCTION_MARKUP_MUSIC full_markup {
-               $$ = scm_list_3 ($1, make_input (@$), $2);
+       ;
+
+function_arglist: EXPECT_NO_MORE_ARGS {
+               /* This is for 0-ary functions, so they don't need to
+                  read a lookahead token */
+               $$ = SCM_EOL;
        }
+       | function_arglist_music_last
+       | function_arglist_nonmusic_last
        ;
 
 generic_prefix_music_scm:
-       music_function_musicless_function {
-               $$ = $1;
-       }
-       | music_function_musicless_prefix music {
-               $$ = ly_append2 ($1, scm_list_1 ($2));
-       }
-       | MUSIC_FUNCTION_MUSIC_MUSIC music music {
-               $$ = scm_list_4 ($1, make_input (@$), $2, $3);
-       }
-       | MUSIC_FUNCTION_SCM_MUSIC_MUSIC function_scm_argument music music {
-               $$ = scm_list_5 ($1, make_input (@$), $2, $3, $4);
-       }
-       | MUSIC_FUNCTION_SCM_SCM_MUSIC_MUSIC function_scm_argument function_scm_argument music music {
-               $$ = scm_list_n ($1, make_input (@$), $2, $3, $4, $5, SCM_UNDEFINED);
-       }
-       | MUSIC_FUNCTION_MARKUP_MUSIC_MUSIC full_markup music music {
-               $$ = scm_list_5 ($1, make_input (@$), $2, $3, $4);
+       MUSIC_FUNCTION function_arglist {
+               $$ = ly_append2 (scm_list_2 ($1, make_input (@$)), scm_reverse_x ($2, SCM_EOL));
        }
        ;
 
@@ -1108,11 +1077,11 @@ mode_changing_head_with_context:
 relative_music:
        RELATIVE absolute_pitch music {
                Pitch start = *unsmob_pitch ($2);
-               $$ = make_music_relative (start, $3);
+               $$ = make_music_relative (start, $3, @$);
        }
        | RELATIVE composite_music {
                Pitch middle_c (0, 0, 0);
-               $$ = make_music_relative (middle_c, $2);
+               $$ = make_music_relative (middle_c, $2, @$);
        }
        ;
 
@@ -1359,9 +1328,8 @@ chord_body_element:
                SCM check = $4;
                SCM post = $5;
 
-               Music *n = MY_MAKE_MUSIC ("NoteEvent");
+               Music *n = MY_MAKE_MUSIC ("NoteEvent", @$);
                n->set_property ("pitch", $1);
-               n->set_spot (@$);
                if (q % 2)
                        n->set_property ("cautionary", SCM_BOOL_T);
                if (ex % 2 || q % 2)
@@ -1380,10 +1348,9 @@ chord_body_element:
                $$ = n->unprotect ();
        }
        | DRUM_PITCH post_events {
-               Music *n = MY_MAKE_MUSIC ("NoteEvent");
+               Music *n = MY_MAKE_MUSIC ("NoteEvent", @$);
                n->set_property ("duration", $2);
                n->set_property ("drum-type", $1);
-               n->set_spot (@$);
 
                if (scm_is_pair ($2)) {
                        SCM arts = scm_reverse_x ($2, SCM_EOL);
@@ -1396,24 +1363,38 @@ chord_body_element:
        }
        ;
 
+music_function_identifier_musicless_prefix: MUSIC_FUNCTION {
+               SCM sig = scm_object_property (yylval.scm, ly_symbol2scm ("music-function-signature"));
+               if (scm_is_pair (sig) && to_boolean (scm_memq (ly_music_p_proc, scm_cdr (scm_reverse (sig)))))
+               {
+                       PARSER->parser_error (@$, "Music function applied to event may not have a Music argument, except as the last argument.");
+               }
+       }
+       ;
+
 music_function_chord_body:
-       music_function_musicless_function {
-               $$ = $1;
+       /* We could allow chord functions to have multiple music arguments,
+          but it's more consistent with music_function_event if we
+          prohibit it here too */
+       music_function_identifier_musicless_prefix EXPECT_MUSIC function_arglist_nonmusic chord_body_element {
+               $$ = ly_append2 (scm_list_2 ($1, make_input (@$)), scm_reverse_x ($3, scm_list_1 ($4)));
        }
-       | music_function_musicless_prefix chord_body_element {
-               $$ = ly_append2 ($1, scm_list_1 ($2));
+       | music_function_identifier_musicless_prefix function_arglist_nonmusic {
+               $$ = ly_append2 (scm_list_2 ($1, make_input (@$)), scm_reverse_x ($2, SCM_EOL));
        }
        ;
 
 music_function_event:
-       music_function_musicless_prefix post_event {
-               $$ = ly_append2 ($1, scm_list_1 ($2));
+       /* Post-events can only have the last argument as music, without this
+          restriction we get a shift/reduce conflict from e.g.
+          c8-\partcombine c8 -. */
+       music_function_identifier_musicless_prefix EXPECT_MUSIC function_arglist_nonmusic post_event {
+               $$ = ly_append2 (scm_list_2 ($1, make_input (@$)), scm_reverse_x ($3, scm_list_1 ($4)));
        }
-       | music_function_musicless_function {
-               $$ = $1;
+       | music_function_identifier_musicless_prefix function_arglist_nonmusic {
+               $$ = ly_append2 (scm_list_2 ($1, make_input (@$)), scm_reverse_x ($2, SCM_EOL));
        }
        ;
-       
 
 command_element:
        command_event {
@@ -1423,15 +1404,13 @@ command_element:
                $$ = MAKE_SYNTAX ("skip-music", @$, $2);
        }
        | E_BRACKET_OPEN {
-               Music *m = MY_MAKE_MUSIC ("LigatureEvent");
+               Music *m = MY_MAKE_MUSIC ("LigatureEvent", @$);
                m->set_property ("span-direction", scm_from_int (START));
-               m->set_spot (@$);
                $$ = m->unprotect();
        }
        | E_BRACKET_CLOSE {
-               Music *m = MY_MAKE_MUSIC ("LigatureEvent");
+               Music *m = MY_MAKE_MUSIC ("LigatureEvent", @$);
                m->set_property ("span-direction", scm_from_int (STOP));
-               m->set_spot (@$);
                $$ = m->unprotect ();
        }
        | E_BACKSLASH {
@@ -1471,22 +1450,22 @@ command_element:
 
 command_event:
        E_TILDE {
-               $$ = MY_MAKE_MUSIC ("PesOrFlexaEvent")->unprotect ();
+               $$ = MY_MAKE_MUSIC ("PesOrFlexaEvent", @$)->unprotect ();
        }
        | MARK DEFAULT  {
-               Music *m = MY_MAKE_MUSIC ("MarkEvent");
+               Music *m = MY_MAKE_MUSIC ("MarkEvent", @$);
                $$ = m->unprotect ();
        }
        | tempo_event {
                $$ = $1;
        }
        | KEY DEFAULT {
-               Music *key = MY_MAKE_MUSIC ("KeyChangeEvent");
+               Music *key = MY_MAKE_MUSIC ("KeyChangeEvent", @$);
                $$ = key->unprotect ();
        }
        | KEY NOTENAME_PITCH SCM_IDENTIFIER     {
 
-               Music *key = MY_MAKE_MUSIC ("KeyChangeEvent");
+               Music *key = MY_MAKE_MUSIC ("KeyChangeEvent", @$);
                if (scm_ilength ($3) > 0)
                {               
                        key->set_property ("pitch-alist", $3);
@@ -1521,12 +1500,12 @@ post_event:
        | HYPHEN {
                if (!PARSER->lexer_->is_lyric_state ())
                        PARSER->parser_error (@1, _ ("have to be in Lyric mode for lyrics"));
-               $$ = MY_MAKE_MUSIC ("HyphenEvent")->unprotect ();
+               $$ = MY_MAKE_MUSIC ("HyphenEvent", @$)->unprotect ();
        }
        | EXTENDER {
                if (!PARSER->lexer_->is_lyric_state ())
                        PARSER->parser_error (@1, _ ("have to be in Lyric mode for lyrics"));
-               $$ = MY_MAKE_MUSIC ("ExtenderEvent")->unprotect ();
+               $$ = MY_MAKE_MUSIC ("ExtenderEvent", @$)->unprotect ();
        }
        | script_dir direction_reqd_event {
                if ($1)
@@ -1549,9 +1528,8 @@ post_event:
 
 string_number_event:
        E_UNSIGNED {
-               Music *s = MY_MAKE_MUSIC ("StringNumberEvent");
+               Music *s = MY_MAKE_MUSIC ("StringNumberEvent", @$);
                s->set_property ("string-number", scm_from_int ($1));
-               s->set_spot (@$);
                $$ = s->unprotect ();
        }
        ;
@@ -1596,20 +1574,19 @@ direction_less_event:
                if (unsmob_music (predefd))
                {
                        m = unsmob_music (predefd)->clone ();
+                       m->set_spot (@$);
                }
                else
                {
-                       m = MY_MAKE_MUSIC ("Music");
+                       m = MY_MAKE_MUSIC ("Music", @$);
                }
-               m->set_spot (@$);
                $$ = m->unprotect ();
        }
        | EVENT_IDENTIFIER      {
                $$ = $1;
        }
        | tremolo_type  {
-               Music *a = MY_MAKE_MUSIC ("TremoloEvent");
-               a->set_spot (@$);
+               Music *a = MY_MAKE_MUSIC ("TremoloEvent", @$);
                a->set_property ("tremolo-type", scm_from_int ($1));
                $$ = a->unprotect ();
         }
@@ -1621,7 +1598,7 @@ direction_reqd_event:
        }
        | script_abbreviation {
                SCM s = PARSER->lexer_->lookup_identifier ("dash" + ly_scm2string ($1));
-               Music *a = MY_MAKE_MUSIC ("ArticulationEvent");
+               Music *a = MY_MAKE_MUSIC ("ArticulationEvent", @$);
                if (scm_is_string (s))
                        a->set_property ("articulation-type", s);
                else PARSER->parser_error (@1, _ ("expecting string as script definition"));
@@ -1704,22 +1681,19 @@ pitch_also_in_chords:
 
 gen_text_def:
        full_markup {
-               Music *t = MY_MAKE_MUSIC ("TextScriptEvent");
+               Music *t = MY_MAKE_MUSIC ("TextScriptEvent", @$);
                t->set_property ("text", $1);
-               t->set_spot (@$);
                $$ = t->unprotect ();
        }
        | string {
-               Music *t = MY_MAKE_MUSIC ("TextScriptEvent");
+               Music *t = MY_MAKE_MUSIC ("TextScriptEvent", @$);
                t->set_property ("text",
                        make_simple_markup ($1));
-               t->set_spot (@$);
                $$ = t->unprotect ();
        }
        | DIGIT {
-               Music *t = MY_MAKE_MUSIC ("FingeringEvent");
+               Music *t = MY_MAKE_MUSIC ("FingeringEvent", @$);
                t->set_property ("digit", scm_from_int ($1));
-               t->set_spot (@$);
                $$ = t->unprotect ();
        }
        ;
@@ -1856,13 +1830,11 @@ figured_bass_alteration:
 
 bass_figure:
        FIGURE_SPACE {
-               Music *bfr = MY_MAKE_MUSIC ("BassFigureEvent");
-               $$ = bfr->self_scm ();
-               bfr->unprotect ();
-               bfr->set_spot (@1);
+               Music *bfr = MY_MAKE_MUSIC ("BassFigureEvent", @$);
+               $$ = bfr->unprotect ();
        }
        | bass_number  {
-               Music *bfr = MY_MAKE_MUSIC ("BassFigureEvent");
+               Music *bfr = MY_MAKE_MUSIC ("BassFigureEvent", @$);
                $$ = bfr->self_scm ();
 
                if (scm_is_number ($1))
@@ -1871,7 +1843,6 @@ bass_figure:
                        bfr->set_property ("text", $1);
 
                bfr->unprotect ();
-               bfr->set_spot (@1);
        }
        | bass_figure ']' {
                $$ = $1;
@@ -1956,9 +1927,9 @@ simple_element:
 
                Music *n = 0;
                if ($6)
-                       n = MY_MAKE_MUSIC ("RestEvent");
+                       n = MY_MAKE_MUSIC ("RestEvent", @$);
                else
-                       n = MY_MAKE_MUSIC ("NoteEvent");
+                       n = MY_MAKE_MUSIC ("NoteEvent", @$);
                
                n->set_property ("pitch", $1);
                n->set_property ("duration", $5);
@@ -1974,11 +1945,10 @@ simple_element:
                if ($2 % 2 || $3 % 2)
                        n->set_property ("force-accidental", SCM_BOOL_T);
 
-               n->set_spot (@$);
                $$ = n->unprotect ();
        }
        | DRUM_PITCH optional_notemode_duration {
-               Music *n = MY_MAKE_MUSIC ("NoteEvent");
+               Music *n = MY_MAKE_MUSIC ("NoteEvent", @$);
                n->set_property ("duration", $2);
                n->set_property ("drum-type", $1);
 
@@ -1988,24 +1958,22 @@ simple_element:
                Music *ev = 0;
                if (ly_scm2string ($1) == "s") {
                        /* Space */
-                       ev = MY_MAKE_MUSIC ("SkipEvent");
+                       ev = MY_MAKE_MUSIC ("SkipEvent", @$);
                  }
                else {
-                       ev = MY_MAKE_MUSIC ("RestEvent");
+                       ev = MY_MAKE_MUSIC ("RestEvent", @$);
                
                    }
                ev->set_property ("duration", $2);
-               ev->set_spot (@$);
                $$ = ev->unprotect ();
        }
        | lyric_element optional_notemode_duration      {
                if (!PARSER->lexer_->is_lyric_state ())
                        PARSER->parser_error (@1, _ ("have to be in Lyric mode for lyrics"));
 
-               Music *levent = MY_MAKE_MUSIC ("LyricEvent");
+               Music *levent = MY_MAKE_MUSIC ("LyricEvent", @$);
                levent->set_property ("text", $1);
                levent->set_property ("duration",$2);
-               levent->set_spot (@$);
                $$= levent->unprotect ();
        }
        ;
@@ -2324,11 +2292,9 @@ markup:
 %%
 
 void
-Lily_parser::set_yydebug (bool )
+Lily_parser::set_yydebug (bool x)
 {
-#if 0
-       yydebug = 1;
-#endif
+       yydebug = x;
 }
 
 void
@@ -2462,6 +2428,13 @@ is_regular_identifier (SCM id)
   return v;
 }
 
+Music *
+make_music_with_input (SCM name, Input where)
+{
+       Music *m = make_music_by_name (name);
+       m->set_spot (where);
+       return m;
+}
 
 SCM
 get_first_context_id (SCM type, Music *m)
@@ -2492,7 +2465,7 @@ void
 set_music_properties (Music *p, SCM a)
 {
   for (SCM k = a; scm_is_pair (k); k = scm_cdr (k))
-       p->internal_set_property (scm_caar (k), scm_cdar (k));
+       p->set_property (scm_caar (k), scm_cdar (k));
 }
 
 
@@ -2526,9 +2499,9 @@ ly_input_procedure_p (SCM x)
 }
 
 SCM
-make_music_relative (Pitch start, SCM music)
+make_music_relative (Pitch start, SCM music, Input loc)
 {
-       Music *relative = MY_MAKE_MUSIC ("RelativeOctaveMusic");
+       Music *relative = MY_MAKE_MUSIC ("RelativeOctaveMusic", loc);
        relative->set_property ("element", music);
        
        Music *m = unsmob_music (music);