@optional_attributes()                 => [ [position, attribute, val]* ]
@optional_attributes("string")         => [ [position, val]* ]
@optional_attributes("string", val)    => [position]*
@optional_attributes(position)         => [ [string, val]* ]
@optional_attributes(position, string) => [val]  or [] if no such attribute

This is an experimental feature

Arbitrary attributes may be defined on a musical event. These attributes associates a value (defined by an arbitrary expression) to an arbitrary name (in the form of a symbol or a string). The function @optional_attributes() is used to query these attributes.

The syntax to define these optionnal attribute is as folows:

    NOTE C4 1 @attribute key1
    NOTE B2 1/2 @attribute "key2"
    CHORD (B2 C4 D3) 1/4 @attribute key3 := expression
    TRILL (B2 C4 D3) 3/2 @attribute "key4" := expression
    EVENT 3 @attribute{ key, "key2", keyWithValue := val2, "kkk" := VAl3, ... } 
The first two form associates only a key to the event: the value is implicitly <undef>. Form 3 and 4 associate a value to a key and the last line shows the general syntax used to associates several attributes to an event.

The function @optional_attributes() is used to retrieve the key/value. The event is specified through its position (in beat). The expression defining the values are evaluated when the score is loaded and a call to @optional_attributes() may appears anywhere.

Example:

// Optional attribute can be query at any time during 
// the execution: the association of an attribute to an 
// event is done when the score is loaded, i.e. before 
// the execution. 

$res := @optional_attributes()
@assert $res.size() == 6
@assert $res.member([0, "RED", <undef>])
@assert $res.member([2, "BLUE", <undef>])
@assert $res.member([2, "RED", <undef>])
@assert $res.member([3, "BLUE", <undef>])
@assert $res.member([3, "first coloratur", "none"])
@assert $res.member([3, "octave", 1])

$res := @optional_attributes("RED")
@assert $res.size() == 2
@assert $res.member([0, <undef>])
@assert $res.member([2, <undef>])

$res := @optional_attributes("octave")
@assert $res.size() == 1
@assert $res.member([3, 1])

$res := @optional_attributes("octave", 0)
@assert $res.empty()

$res := @optional_attributes("octave", 1)
@assert $res.size() == 1
@assert $res.member(3)

$res := @optional_attributes(1)
@assert $res.empty()

$res := @optional_attributes(2)
@assert $res.member([2.0, "BLUE", <undef>])
@assert $res.member([2.0, "RED", <undef>])

$res := @optional_attributes(3, "first coloratur")
@assert $res == ["none"]


$res := @optional_attributes(3, "octave")
@assert $res == [1]

$res := @optional_attributes(3, "BLUE")
@assert $res == [<undef>]

$res := @optional_attributes(3, "TicToc")
@assert $res == []


NOTE C1 1.0 @attr::RED

NOTE D4 1

NOTE C2 1 @attr::{RED, BLUE}

NOTE C3 1 @attr::{ octave := 1, "first coloratur" := "none", BLUE }

NOTE D5 1

See also: Score Introspection

[@always_next_event_except_sil_pos]   @bach_score   @current_event   @event_label_position   @make_bpm_map   @make_bpm_tab   @make_duration_map   @make_duration_tab   @make_label_bpm   @make_label_duration   @make_label_pitches   @make_label_pos   @make_pitch_tab   @make_score_map   [@next_event_except_sil_pos]   [@next_event_with_sil_pos]   [@next_sil_pos]   @optional_attributes    @performance_data    @score_duration    @score_tempi   @specified_duration