2 stem.cc -- implement Stem
4 source file of the GNU LilyPond music typesetter
6 (c) 1996--2006 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 Jan Nieuwenhuizen <janneke@gnu.org>
9 TODO: This is way too hairy
13 Stem-end, chord-start, etc. is all confusing naming.
18 #include <cmath> // rint
22 #include "directional-element-interface.hh"
23 #include "dot-column.hh"
24 #include "font-interface.hh"
25 #include "international.hh"
28 #include "note-head.hh"
29 #include "output-def.hh"
30 #include "paper-column.hh"
31 #include "pointer-group-interface.hh"
33 #include "rhythmic-head.hh"
34 #include "side-position-interface.hh"
35 #include "staff-symbol-referencer.hh"
36 #include "stem-tremolo.hh"
40 Stem::set_beaming (Grob *me, int beam_count, Direction d)
42 SCM pair = me->get_property ("beaming");
44 if (!scm_is_pair (pair))
46 pair = scm_cons (SCM_EOL, SCM_EOL);
47 me->set_property ("beaming", pair);
50 SCM lst = index_get_cell (pair, d);
52 for (int i = 0; i < beam_count; i++)
53 lst = scm_cons (scm_from_int (i), lst);
57 index_set_cell (pair, d, lst);
61 Stem::get_beaming (Grob *me, Direction d)
63 SCM pair = me->get_property ("beaming");
64 if (!scm_is_pair (pair))
67 SCM lst = index_get_cell (pair, d);
68 return scm_ilength (lst);
72 Stem::head_positions (Grob *me)
76 Drul_array<Grob *> e (extremal_heads (me));
77 return Interval (Staff_symbol_referencer::get_position (e[DOWN]),
78 Staff_symbol_referencer::get_position (e[UP]));
84 Stem::chord_start_y (Grob *me)
86 Interval hp = head_positions (me);
88 return hp[get_grob_direction (me)] * Staff_symbol_referencer::staff_space (me)
96 Stem::set_stemend (Grob *me, Real se)
99 Direction d = get_grob_direction (me);
101 if (d && d * head_positions (me)[get_grob_direction (me)] >= se * d)
102 me->warning (_ ("weird stem size, check for narrow beams"));
104 me->set_property ("stem-end-position", scm_from_double (se));
107 /* Note head that determines hshift for upstems
108 WARNING: triggers direction */
110 Stem::support_head (Grob *me)
112 extract_grob_set (me, "note-heads", heads);
113 if (heads.size () == 1)
116 return first_head (me);
120 Stem::head_count (Grob *me)
122 return Pointer_group_interface::count (me, ly_symbol2scm ("note-heads"));
125 /* The note head which forms one end of the stem.
126 WARNING: triggers direction */
128 Stem::first_head (Grob *me)
130 Direction d = get_grob_direction (me);
132 return extremal_heads (me)[-d];
136 /* The note head opposite to the first head. */
138 Stem::last_head (Grob *me)
140 Direction d = get_grob_direction (me);
142 return extremal_heads (me)[d];
147 START is part where stem reaches `last' head.
149 This function returns a drul with (bottom-head, top-head).
152 Stem::extremal_heads (Grob *me)
154 const int inf = 1000000;
155 Drul_array<int> extpos;
159 Drul_array<Grob *> exthead (0, 0);
160 extract_grob_set (me, "note-heads", heads);
162 for (vsize i = heads.size (); i--;)
165 int p = Staff_symbol_referencer::get_rounded_position (n);
170 if (d * p > d * extpos[d])
176 while (flip (&d) != DOWN);
182 integer_compare (int const &a, int const &b)
187 /* The positions, in ascending order. */
189 Stem::note_head_positions (Grob *me)
192 extract_grob_set (me, "note-heads", heads);
194 for (vsize i = heads.size (); i--;)
197 int p = Staff_symbol_referencer::get_rounded_position (n);
202 vector_sort (ps, integer_compare);
207 Stem::add_head (Grob *me, Grob *n)
209 n->set_object ("stem", me->self_scm ());
211 if (Note_head::has_interface (n))
212 Pointer_group_interface::add_grob (me, ly_symbol2scm ("note-heads"), n);
213 else if (Rest::has_interface (n))
214 Pointer_group_interface::add_grob (me, ly_symbol2scm ("rests"), n);
218 Stem::is_invisible (Grob *me)
220 Real stemlet_length = robust_scm2double (me->get_property ("stemlet-length"),
223 return !((head_count (me)
224 || stemlet_length > 0.0)
225 && scm_to_int (me->get_property ("duration-log")) >= 1);
228 MAKE_SCHEME_CALLBACK (Stem, pure_height, 3)
230 Stem::pure_height (SCM smob, SCM start, SCM end)
236 Grob *me = unsmob_grob (smob);
237 Real ss = Staff_symbol_referencer::staff_space (me);
238 Real len = scm_to_double (calc_length (smob)) * ss / 2;
239 Direction dir = get_grob_direction (me);
242 Interval hp = head_positions (me);
244 iv = Interval (0, len);
246 iv = Interval (-len, 0);
249 iv.translate (hp[dir] * ss / 2);
251 return ly_interval2scm (iv);
254 MAKE_SCHEME_CALLBACK (Stem, calc_stem_end_position, 1)
256 Stem::calc_stem_end_position (SCM smob)
258 Grob *me = unsmob_grob (smob);
260 if (!head_count (me))
261 return scm_from_double (0.0);
263 if (Grob *beam = unsmob_grob (me->get_object ("beam")))
265 (void) beam->get_property ("quantized-positions");
266 return me->get_property ("stem-end-position");
269 Real ss = Staff_symbol_referencer::staff_space (me);
270 int durlog = duration_log (me);
273 /* WARNING: IN HALF SPACES */
274 Real length = robust_scm2double (me->get_property ("length"), 7);
276 Direction dir = get_grob_direction (me);
277 Interval hp = head_positions (me);
278 Real stem_end = dir ? hp[dir] + dir * length : 0;
280 /* TODO: change name to extend-stems to staff/center/'() */
281 bool no_extend_b = to_boolean (me->get_property ("no-stem-extend"));
282 if (!no_extend_b && dir * stem_end < 0)
286 /* Make a little room if we have a upflag and there is a dot.
287 previous approach was to lengthen the stem. This is not
288 good typesetting practice. */
289 if (!get_beam (me) && dir == UP
292 Grob *closest_to_flag = extremal_heads (me)[dir];
293 Grob *dots = closest_to_flag
294 ? Rhythmic_head::get_dots (closest_to_flag) : 0;
298 Real dp = Staff_symbol_referencer::get_position (dots);
299 Interval flag_yext = flag (me).extent (Y_AXIS) * (2 / ss) + stem_end;
301 /* Very gory: add myself to the X-support of the parent,
302 which should be a dot-column. */
304 if (flag_yext.distance (dp) < 0.5)
306 Grob *par = dots->get_parent (X_AXIS);
308 if (Dot_column::has_interface (par))
310 Side_position_interface::add_support (par, me);
312 /* TODO: apply some better logic here. The flag is
313 curved inwards, so this will typically be too
320 return scm_from_double (stem_end);
324 MAKE_SCHEME_CALLBACK (Stem, calc_length, 1)
326 Stem::calc_length (SCM smob)
328 Grob *me = unsmob_grob (smob);
330 SCM details = me->get_property ("details");
331 int durlog = duration_log (me);
333 Real ss = Staff_symbol_referencer::staff_space (me);
335 SCM s = scm_cdr (scm_assq (ly_symbol2scm ("lengths"), details));
337 length = 2 * scm_to_double (robust_list_ref (durlog - 2, s));
339 Direction dir = get_grob_direction (me);
341 /* Stems in unnatural (forced) direction should be shortened,
342 according to [Roush & Gourlay] */
343 Interval hp = head_positions (me);
344 if (dir && dir * hp[dir] >= 0)
346 SCM sshorten = scm_cdr (scm_assq (ly_symbol2scm ("stem-shorten"), details));
347 SCM scm_shorten = scm_is_pair (sshorten)
348 ? robust_list_ref (max (duration_log (me) - 2, 0), sshorten) : SCM_EOL;
349 Real shorten = 2* robust_scm2double (scm_shorten, 0);
351 /* On boundary: shorten only half */
352 if (abs (head_positions (me)[dir]) <= 1)
358 length *= robust_scm2double (me->get_property ("length-fraction"), 1.0);
361 Grob *t_flag = unsmob_grob (me->get_object ("tremolo-flag"));
362 if (t_flag && !unsmob_grob (me->get_object ("beam")))
364 /* Crude hack: add extra space if tremolo flag is there.
366 We can't do this for the beam, since we get into a loop
367 (Stem_tremolo::raw_stencil () looks at the beam.) --hwn */
370 + 2 * t_flag->extent (t_flag, Y_AXIS).length ()
373 /* We don't want to add the whole extent of the flag because the trem
374 and the flag can overlap partly. beam_translation gives a good
378 Real beam_trans = Stem_tremolo::get_beam_translation (t_flag);
379 /* the obvious choice is (durlog - 2) here, but we need a bit more space. */
380 minlen += 2 * (durlog - 1.5) * beam_trans;
382 /* up-stems need even a little more space to avoid collisions. This
383 needs to be in sync with the tremolo positioning code in
384 Stem_tremolo::print */
386 minlen += beam_trans;
388 length = max (length, minlen + 1.0);
391 return scm_from_double (length);
393 /* The log of the duration (Number of hooks on the flag minus two) */
395 Stem::duration_log (Grob *me)
397 SCM s = me->get_property ("duration-log");
398 return (scm_is_number (s)) ? scm_to_int (s) : 2;
401 MAKE_SCHEME_CALLBACK(Stem, calc_positioning_done, 1);
403 Stem::calc_positioning_done (SCM smob)
405 Grob *me = unsmob_grob (smob);
406 if (!head_count (me))
409 extract_grob_set (me, "note-heads", ro_heads);
410 vector<Grob*> heads (ro_heads);
411 vector_sort (heads, compare_position);
412 Direction dir = get_grob_direction (me);
417 Real thick = thickness (me);
419 Grob *hed = support_head (me);
422 programming_error ("Stem dir must be up or down.");
424 set_grob_direction (me, dir);
427 Real w = hed->extent (hed, X_AXIS)[dir];
428 for (vsize i = 0; i < heads.size (); i++)
429 heads[i]->translate_axis (w - heads[i]->extent (heads[i], X_AXIS)[dir],
433 Real lastpos = Real (Staff_symbol_referencer::get_position (heads[0]));
434 for (vsize i = 1; i < heads.size (); i++)
436 Real p = Staff_symbol_referencer::get_position (heads[i]);
437 Real dy = fabs (lastpos- p);
440 dy should always be 0.5, 0.0, 1.0, but provide safety margin
447 Real ell = heads[i]->extent (heads[i], X_AXIS).length ();
449 Direction d = get_grob_direction (me);
451 Reversed head should be shifted ell-thickness, but this
452 looks too crowded, so we only shift ell-0.5*thickness.
454 This leads to assymetry: Normal heads overlap the
455 stem 100% whereas reversed heads only overlaps the
459 Real reverse_overlap = 0.5;
460 heads[i]->translate_axis ((ell - thick * reverse_overlap) * d,
463 if (is_invisible (me))
464 heads[i]->translate_axis (-thick * (2 - reverse_overlap) * d,
469 For some cases we should kern some more: when the
470 distance between the next or prev note is too large, we'd
471 get large white gaps, eg.
492 MAKE_SCHEME_CALLBACK(Stem, calc_direction, 1);
494 Stem::calc_direction (SCM smob)
496 Grob *me = unsmob_grob (smob);
497 Direction dir = CENTER;
498 if (Grob *beam = unsmob_grob (me->get_object ("beam")))
500 SCM ignore_me = beam->get_property ("direction");
502 dir = get_grob_direction (me);
506 SCM dd = me->get_property ("default-direction");
509 return me->get_property ("neutral-direction");
512 return scm_from_int (dir);
515 MAKE_SCHEME_CALLBACK(Stem, calc_default_direction, 1);
517 Stem::calc_default_direction (SCM smob)
519 Grob *me = unsmob_grob (smob);
521 Direction dir = CENTER;
522 int staff_center = 0;
523 Interval hp = head_positions (me);
526 int udistance = (int) (UP * hp[UP] - staff_center);
527 int ddistance = (int) (DOWN * hp[DOWN] - staff_center);
529 dir = Direction (sign (ddistance - udistance));
532 return scm_from_int (dir);
536 MAKE_SCHEME_CALLBACK (Stem, height, 1);
538 Stem::height (SCM smob)
540 Grob *me = unsmob_grob (smob);
542 Direction dir = get_grob_direction (me);
546 UGH. Should be automatic
548 Grob *beam = get_beam (me);
551 /* trigger set-stem-lengths. */
552 beam->get_property ("quantized-positions");
556 Can't get_stencil(), since that would cache stencils too early.
557 This causes problems with beams.
559 Stencil *stencil = unsmob_stencil (print (smob));
560 Interval iv = stencil ? stencil->extent (Y_AXIS) : Interval();
565 programming_error ("no stem direction");
568 iv[dir] += dir * Beam::get_thickness (beam) * 0.5;
571 return ly_interval2scm (iv);
575 Stem::stem_end_position (Grob *me)
577 return robust_scm2double (me->get_property ("stem-end-position"), 0);
581 Stem::flag (Grob *me)
583 int log = duration_log (me);
585 || unsmob_grob (me->get_object ("beam")))
589 TODO: maybe property stroke-style should take different values,
590 e.g. "" (i.e. no stroke), "single" and "double" (currently, it's
594 SCM flag_style_scm = me->get_property ("flag-style");
595 if (scm_is_symbol (flag_style_scm))
596 flag_style = ly_symbol2string (flag_style_scm);
598 if (flag_style == "no-flag")
603 string staffline_offs;
604 if (flag_style == "mensural")
605 /* Mensural notation: For notes on staff lines, use different
606 flags than for notes between staff lines. The idea is that
607 flags are always vertically aligned with the staff lines,
608 regardless if the note head is on a staff line or between two
609 staff lines. In other words, the inner end of a flag always
610 touches a staff line.
615 int p = (int) (rint (stem_end_position (me)));
617 = Staff_symbol_referencer::on_line (me, p) ? "0" : "1";
620 staffline_offs = "2";
625 char dir = (get_grob_direction (me) == UP) ? 'u' : 'd';
626 string font_char = flag_style
627 + to_string (dir) + staffline_offs + to_string (log);
628 Font_metric *fm = Font_interface::get_default_font (me);
629 Stencil flag = fm->find_by_name ("flags." + font_char);
630 if (flag.is_empty ())
631 me->warning (_f ("flag `%s' not found", font_char));
633 SCM stroke_style_scm = me->get_property ("stroke-style");
634 if (scm_is_string (stroke_style_scm))
636 string stroke_style = ly_scm2string (stroke_style_scm);
637 if (!stroke_style.empty ())
639 string font_char = to_string (dir) + stroke_style;
640 Stencil stroke = fm->find_by_name ("flags." + font_char);
641 if (stroke.is_empty ())
642 me->warning (_f ("flag stroke `%s' not found", font_char));
644 flag.add_stencil (stroke);
651 MAKE_SCHEME_CALLBACK (Stem, width, 1);
655 Grob *me = unsmob_grob (e);
659 if (is_invisible (me))
661 else if (unsmob_grob (me->get_object ("beam"))
662 || abs (duration_log (me)) <= 2)
664 r = Interval (-1, 1);
665 r *= thickness (me) / 2;
669 r = Interval (-1, 1) * thickness (me) * 0.5;
670 r.unite (flag (me).extent (X_AXIS));
672 return ly_interval2scm (r);
676 Stem::thickness (Grob *me)
678 return scm_to_double (me->get_property ("thickness"))
679 * Staff_symbol_referencer::line_thickness (me);
682 MAKE_SCHEME_CALLBACK (Stem, print, 1);
684 Stem::print (SCM smob)
686 Grob *me = unsmob_grob (smob);
688 Direction d = get_grob_direction (me);
690 Real stemlet_length = robust_scm2double (me->get_property ("stemlet-length"),
692 bool stemlet = stemlet_length > 0.0;
694 /* TODO: make the stem start a direction ?
695 This is required to avoid stems passing in tablature chords. */
697 = to_boolean (me->get_property ("avoid-note-head"))
700 Grob *beam = get_beam (me);
705 if (!lh && stemlet && !beam)
708 if (is_invisible (me))
711 Real y2 = robust_scm2double (me->get_property ("stem-end-position"), 0.0);
713 Real half_space = Staff_symbol_referencer::staff_space (me) * 0.5;
716 y2 = Staff_symbol_referencer::get_position (lh);
719 Real beam_translation = Beam::get_beam_translation (beam);
720 Real beam_thickness = Beam::get_thickness (beam);
721 int beam_count = beam_multiplicity (me).length () + 1;
724 * (0.5 * beam_thickness
725 + beam_translation * max (0, (beam_count - 1))
726 + stemlet_length) / half_space;
729 Interval stem_y (min (y1, y2), max (y2, y1));
731 if (Grob *head = support_head (me))
734 must not take ledgers into account.
736 Interval head_height = head->extent (head, Y_AXIS);
737 Real y_attach = Note_head::stem_attachment_coordinate (head, Y_AXIS);
739 y_attach = head_height.linear_combination (y_attach);
740 stem_y[Direction (-d)] += d * y_attach / half_space;
744 Real stem_width = thickness (me);
746 = me->layout ()->get_dimension (ly_symbol2scm ("blot-diameter"));
748 Box b = Box (Interval (-stem_width / 2, stem_width / 2),
749 Interval (stem_y[DOWN] * half_space, stem_y[UP] * half_space));
751 Stencil ss = Lookup::round_filled_box (b, blot);
752 mol.add_stencil (ss);
754 mol.add_stencil (get_translated_flag (me));
756 return mol.smobbed_copy ();
760 Stem::get_translated_flag (Grob *me)
762 Stencil fl = flag (me);
765 Direction d = get_grob_direction (me);
767 = me->layout ()->get_dimension (ly_symbol2scm ("blot-diameter"));
768 Real stem_width = thickness (me);
769 Real half_space = Staff_symbol_referencer::staff_space (me) * 0.5;
770 Real y2 = robust_scm2double (me->get_property ("stem-end-position"), 0.0);
771 fl.translate_axis (y2 * half_space - d * blot / 2, Y_AXIS);
772 fl.translate_axis (stem_width / 2, X_AXIS);
779 move the stem to right of the notehead if it is up.
781 MAKE_SCHEME_CALLBACK (Stem, offset_callback, 1);
783 Stem::offset_callback (SCM smob)
785 Grob *me = unsmob_grob (smob);
788 if (Grob *f = first_head (me))
790 Interval head_wid = f->extent (f, X_AXIS);
793 if (is_invisible (me))
796 attach = Note_head::stem_attachment_coordinate (f, X_AXIS);
798 Direction d = get_grob_direction (me);
799 Real real_attach = head_wid.linear_combination (d * attach);
802 /* If not centered: correct for stem thickness. */
805 Real rule_thick = thickness (me);
806 r += -d * rule_thick * 0.5;
811 extract_grob_set (me, "rests", rests);
814 Grob *rest = rests.back ();
815 r = rest->extent (rest, X_AXIS).center ();
818 return scm_from_double (r);
822 Stem::get_beam (Grob *me)
824 SCM b = me->get_object ("beam");
825 return dynamic_cast<Spanner *> (unsmob_grob (b));
829 Stem::get_stem_info (Grob *me)
832 si.dir_ = get_grob_direction (me);
834 SCM scm_info = me->get_property ("stem-info");
835 si.ideal_y_ = scm_to_double (scm_car (scm_info));
836 si.shortest_y_ = scm_to_double (scm_cadr (scm_info));
840 MAKE_SCHEME_CALLBACK(Stem, calc_stem_info, 1);
842 Stem::calc_stem_info (SCM smob)
844 Grob *me = unsmob_grob (smob);
845 Direction my_dir = get_grob_direction (me);
849 programming_error ("no stem dir set");
853 Real staff_space = Staff_symbol_referencer::staff_space (me);
854 Grob *beam = get_beam (me);
858 (void) beam->get_property ("beaming");
861 Real beam_translation = Beam::get_beam_translation (beam);
862 Real beam_thickness = Beam::get_thickness (beam);
863 int beam_count = Beam::get_direction_beam_count (beam, my_dir);
865 = robust_scm2double (me->get_property ("length-fraction"), 1.0);
867 /* Simple standard stem length */
868 SCM details = me->get_property ("details");
869 SCM lengths = scm_cdr (scm_assq (ly_symbol2scm ("beamed-lengths"), details));
872 = scm_to_double (robust_list_ref (beam_count - 1, lengths))
876 /* stem only extends to center of beam
878 - 0.5 * beam_thickness;
880 /* Condition: sane minimum free stem length (chord to beams) */
881 lengths = scm_cdr (scm_assq (ly_symbol2scm ("beamed-minimum-free-lengths"), details));
883 Real ideal_minimum_free
884 = scm_to_double (robust_list_ref (beam_count - 1, lengths))
888 Real height_of_my_trem = 0.0;
889 Grob *trem = unsmob_grob (me->get_object ("tremolo-flag"));
891 height_of_my_trem = trem->extent (trem, Y_AXIS).length ()
892 /* hack a bit of space around the trem. */
896 It seems that also for ideal minimum length, we must use
897 the maximum beam count (for this direction):
899 \score{ \notes\relative c''{ [a8 a32] }}
901 must be horizontal. */
902 Real height_of_my_beams = beam_thickness
903 + (beam_count - 1) * beam_translation;
905 Real ideal_minimum_length = ideal_minimum_free
908 /* stem only extends to center of beam */
909 - 0.5 * beam_thickness;
911 ideal_length = max (ideal_length, ideal_minimum_length);
913 /* Convert to Y position, calculate for dir == UP */
915 = /* staff positions */
916 head_positions (me)[my_dir] * 0.5
917 * my_dir * staff_space;
918 Real ideal_y = note_start + ideal_length;
920 /* Conditions for Y position */
922 /* Lowest beam of (UP) beam must never be lower than second staffline
926 Although this (additional) rule is probably correct,
927 I expect that highest beam (UP) should also never be lower
928 than middle staffline, just as normal stems.
932 Obviously not for grace beams.
934 Also, not for knees. Seems to be a good thing. */
935 bool no_extend_b = to_boolean (me->get_property ("no-stem-extend"));
936 bool is_knee = to_boolean (beam->get_property ("knee"));
937 if (!no_extend_b && !is_knee)
939 /* Highest beam of (UP) beam must never be lower than middle
941 ideal_y = max (ideal_y, 0.0);
942 /* Lowest beam of (UP) beam must never be lower than second staffline */
943 ideal_y = max (ideal_y, (-staff_space
944 - beam_thickness + height_of_my_beams));
947 ideal_y -= robust_scm2double (beam->get_property ("shorten"), 0);
949 SCM bemfl = scm_cdr (scm_assq (ly_symbol2scm ("beamed-extreme-minimum-free-lengths"),
953 = scm_to_double (robust_list_ref (beam_count - 1, bemfl))
957 Real minimum_length = max (minimum_free, height_of_my_trem)
959 /* stem only extends to center of beam */
960 - 0.5 * beam_thickness;
963 Real minimum_y = note_start + minimum_length;
964 Real shortest_y = minimum_y * my_dir;
966 return scm_list_2 (scm_from_double (ideal_y),
967 scm_from_double (shortest_y));
971 Stem::beam_multiplicity (Grob *stem)
973 SCM beaming = stem->get_property ("beaming");
974 Slice le = int_list_to_slice (scm_car (beaming));
975 Slice ri = int_list_to_slice (scm_cdr (beaming));
980 /* FIXME: Too many properties */
981 ADD_INTERFACE (Stem, "stem-interface",
982 "The stem represent the graphical stem. "
983 "In addition, it internally connects note heads, beams and"
985 "Rests and whole notes have invisible stems."
987 "\n\nThe following properties may be set in the details list."
989 "@item beamed-lengths \n"
990 "list of stem lengths given beam multiplicity. \n"
991 "@item beamed-minimum-free-lengths \n"
992 "list of normal minimum free stem lengths (chord to beams) given beam multiplicity.\n"
993 "@item beamed-extreme-minimum-free-lengths\n"
994 "list of extreme minimum free stem lengths (chord to beams) given beam multiplicity.\n"
996 "Default stem lengths. The list gives a length for each flag-count.\n"
997 "@item stem-shorten\n"
998 "How much a stem in a forced direction "
999 "should be shortened. The list gives an amount depending on the number "
1008 "default-direction "
1017 "neutral-direction "
1022 "stem-end-position "
1030 /****************************************************************/
1032 Stem_info::Stem_info ()
1034 ideal_y_ = shortest_y_ = 0;
1039 Stem_info::scale (Real x)