+ // allow override of ledger positions via note head grob...
+ if (head)
+ {
+ SCM posns = head->get_property ("ledger-positions");
+ if (scm_is_pair (posns))
+ return ly_scm2floatvector (posns);
+ }
+
+ // ...or via custom ledger positions function
+ SCM lp_function = me->get_property ("ledger-positions-function");
+ if (scm_is_pair (lp_function))
+ {
+ SCM func = scm_eval (lp_function, scm_interaction_environment ());
+ if (ly_is_procedure (func))
+ return ly_scm2floatvector (scm_call_2 (func,
+ me->self_scm (),
+ scm_from_int (pos)));
+ }
+
+ SCM ledger_positions = me->get_property ("ledger-positions");
+ Real ledger_extra = robust_scm2double (me->get_property ("ledger-extra"), 0);
+ vector<Real> line_positions = Staff_symbol::line_positions (me);
+ vector<Real> values;
+
+ if (line_positions.empty ())
+ return values;
+
+ // find the staff line nearest to note position
+ Real nearest_line = line_positions[0];
+ Real line_dist = abs (line_positions[0] - pos);
+ for (vector<Real>::const_iterator i = line_positions.begin (),
+ e = line_positions.end ();
+ i != e;
+ ++i)
+ {
+ if (abs (*i - pos) < line_dist)
+ {
+ nearest_line = *i;
+ line_dist = abs (*i - pos);
+ }
+ }
+
+ if (line_dist < .5)
+ return values;
+
+ Direction dir = (Direction)sign (pos - nearest_line);
+
+ if (scm_is_pair (ledger_positions))
+ // custom ledger positions via StaffSymbol.ledger-positions
+ {
+ Real min_pos = HUGE_VAL;
+ Real max_pos = -HUGE_VAL;
+ SCM s2;
+
+ // find the extent of the ledger pattern
+ for (SCM s = ledger_positions; scm_is_pair (s); s = scm_cdr (s))
+ {
+ s2 = scm_car (s);
+ if (!scm_is_number (s2))
+ s2 = scm_car (s2);
+ Real current_ledger = scm_to_double (s2);
+ if (current_ledger > max_pos)
+ max_pos = current_ledger;
+ if (current_ledger < min_pos)
+ min_pos = current_ledger;
+ }
+
+ Real cycle = max_pos - min_pos;
+
+ Interval ledger_fill;
+ ledger_fill.add_point (nearest_line + 0.5 * dir);
+ ledger_fill.add_point (pos + 0.5 * dir + ledger_extra * dir);
+
+ // fill the Interval ledger_fill with ledger lines
+ int n = (int) floor ((ledger_fill[DOWN] - min_pos) / cycle);
+ Real current;
+ SCM s = scm_cdr (ledger_positions);
+ if (!scm_is_pair (s) || cycle < 0.1)
+ return values;
+ do
+ {
+ s2 = scm_car (s);
+ if (scm_is_number (s2))
+ {
+ current = scm_to_double (s2) + n * cycle;
+ if (ledger_fill.contains (current))
+ values.push_back (current);
+ }
+ else
+ // grouped ledger lines, either add all or none
+ {
+ do
+ {
+ current = scm_to_double (scm_car (s2)) + n * cycle;
+ if (ledger_fill.contains (current))
+ {
+ s2 = scm_car (s);
+ do
+ {
+ current = scm_to_double (scm_car (s2)) + n * cycle;
+ values.push_back (current);
+ s2 = scm_cdr (s2);
+ }
+ while (scm_is_pair (s2));
+ }
+ else
+ s2 = scm_cdr (s2);
+ }
+ while (scm_is_pair (s2));
+ }
+ s = scm_cdr (s);
+ if (!scm_is_pair (s))
+ {
+ s = scm_cdr (ledger_positions);
+ n++;
+ }
+ }
+ while (current <= ledger_fill[UP]);
+ }
+ else
+ // normal ledger lines
+ {
+ int ledger_count = (int) floor ((abs (nearest_line - pos) + ledger_extra) / 2);
+ values.resize (ledger_count);
+ for (int i = 0; i < ledger_count; i++)
+ {
+ values[i] = nearest_line + dir * (ledger_count - i) * 2;
+ }
+ }
+ // remove any ledger lines that would fall on staff lines,
+ // which can happen when ledger-extra > 0
+ vector<Real> final_values;
+ for (vector<Real>::const_iterator i = values.begin (),
+ e = values.end ();
+ i != e;
+ ++i)
+ {
+ if (find (line_positions.begin (), line_positions.end (), *i) == line_positions.end ())
+ {
+ final_values.push_back (*i);
+ }
+ }
+ return final_values;