1 @c -*- coding: utf-8; mode: texinfo; -*-
4 Translation of GIT committish: FILL-IN-HEAD-COMMITTISH
6 When revising a translation, copy the HEAD committish of the
7 version that you are working on. See TRANSLATION for details.
13 @chapter Scheme tutorial
18 @cindex Scheme, in-line code
19 @cindex accessing Scheme
20 @cindex evaluating Scheme
23 LilyPond uses the Scheme programming language, both as part of the
24 input syntax, and as internal mechanism to glue modules of the program
25 together. This section is a very brief overview of entering data in
26 Scheme. If you want to know more about Scheme, see
27 @uref{http://@/www@/.schemers@/.org}.
29 LilyPond uses the GNU Guile implementation of Scheme, which is
30 based on the Scheme @qq{R5RS} standard. If you are learning Scheme
31 to use with LilyPond, working with a different implementation (or
32 referring to a different standard) is not recommended. Information
33 on guile can be found at @uref{http://www.gnu.org/software/guile/}.
34 The @qq{R5RS} Scheme standard is located at
35 @uref{http://www.schemers.org/Documents/Standards/R5RS/}.
38 * Introduction to Scheme::
39 * Scheme in LilyPond::
40 * Building complicated functions::
43 @node Introduction to Scheme
44 @section Introduction to Scheme
46 We begin with an introduction to Scheme. For this brief introduction,
47 we will use the GUILE interpreter to explore how the language works.
48 Once we are familiar with Scheme, we will show how the language can
49 be integrated in LilyPond files.
55 * Scheme simple data types::
56 * Scheme compound data types::
57 * Calculations in Scheme::
59 * Scheme conditionals::
63 @subsection Scheme sandbox
65 The LilyPond installation includes the Guile implementation of
66 Scheme. On most systems you can experiment in a Scheme sandbox by
67 opening a terminal window and typing @q{guile}. On some systems,
68 notably Windows, you may need to set the environment variable
69 @code{GUILE_LOAD_PATH} to the directory @code{../usr/shr/guile/1.8}
70 in the LilyPond installation. For the full path to this directory
71 see @rlearning{Other sources of information}. Alternatively, Windows
72 users may simply choose @q{Run} from the Start menu and enter
75 Once the guile sandbox is running, you will received a guile prompt:
81 You can enter Scheme expressions at this prompt to experiment with Scheme.
83 @node Scheme variables
84 @subsection Scheme variables
86 Scheme variables can have any valid scheme value, including a Scheme
89 Scheme variables are created with @code{define}:
96 Scheme variables can be evaluated at the guile prompt simply by
97 typing the variable name:
105 Scheme variables can be printed on the display by use of the display function:
113 Note that the value @code{2} and the guile prompt @code{guile} both
114 showed up on the same line. This can be avoided by calling the newline
115 procedure or displaying a newline character.
118 guile> (display a)(newline)
120 guile> (display a)(display "\n")
125 Once a variable has been created, its value can be changed with @code{set!}:
128 guile> (set! a 12345)
134 @node Scheme simple data types
135 @subsection Scheme simple data types
137 The most basic concept in a language is data typing: numbers, character
138 strings, lists, etc. Here is a list of simple Scheme data types that are
139 often used with LilyPond.
143 Boolean values are True or False. The Scheme for True is @code{#t}
144 and False is @code{#f}.
149 Numbers are entered in the standard fashion,
150 @code{1} is the (integer) number one, while @code{-1.5} is a
151 floating point number (a non-integer number).
154 Strings are enclosed in double quotes,
160 Strings may span several lines:
169 and the newline characters at the end of each line will be included
172 Newline characters can also be added by including @code{\n} in the
176 "this\nis a\nmultiline string"
180 Quotation marks and backslashes are added to strings
181 by preceding them with a backslash.
182 The string @code{\a said "b"} is entered as
190 There are additional Scheme data types that are not discussed here.
191 For a complete listing see the Guile reference guide,
192 @uref{http://www.gnu.org/software/guile/manual/html_node/Simple-Data-Types.html}.
194 @node Scheme compound data types
195 @subsection Scheme compound data types
197 There are also compound data types in Scheme. The types commonly used in
198 LilyPond programming include pairs, lists, alists, and hash tables.
200 @unnumberedsubsubsec Pairs
202 The foundational compound data type of Scheme is the @code{pair}. As
203 might be expected from its name, a pair is two values glued together.
204 The operator used to form a pair is called @code{cons}.
212 Note that the pair is displayed as two items surrounded by
213 parentheses and separated by whitespace, a period (@code{.}), and
214 more whitespace. The period is @emph{not} a decimal point, but
215 rather an indicator of the pair.
217 Pairs can also be entered as literal values by preceding them with
218 a single quote character.
226 The two elements of a pair may be any valid Scheme value:
231 guile> '("blah-blah" . 3.1415926535)
232 ("blah-blah" . 3.1415926535)
236 The first and second elements of the pair can be accessed by the
237 Scheme procedures @code{car} and @code{cdr}, respectively.
240 guile> (define mypair (cons 123 "hello there")
251 Note: @code{cdr} is pronounced "could-er", according Sussman and
253 @uref{http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-14.html#footnote_Temp_133}
256 @unnumberedsubsubsec Lists
258 TODO -- write about lists
260 A list is entered by enclosing its elements in parentheses, and adding
261 a quote. For example,
268 We have been using lists all along. A calculation, like @code{(+ 1 2)}
269 is also a list (containing the symbol @code{+} and the numbers 1
270 and@tie{}2). Normally lists are interpreted as calculations, and the
271 Scheme interpreter substitutes the outcome of the calculation. To enter a
272 list, we stop the evaluation. This is done by quoting the list with a
273 quote @code{'} symbol. So, for calculations do not use a quote.
275 Inside a quoted list or pair, there is no need to quote anymore. The
276 following is a pair of symbols, a list of symbols and a list of lists
281 #'(staff clef key-signature)
285 @unnumberedsubsubsec Hash tables
287 TODO -- write about hash tables
290 @node Calculations in Scheme
291 @subsection Calculations in Scheme
293 Scheme can be used to do calculations. It uses @emph{prefix}
294 syntax. Adding 1 and@tie{}2 is written as @code{(+ 1 2)} rather than the
295 traditional @math{1+2}.
302 The arrow @result{} shows that the result of evaluating @code{(+ 1 2)}
303 is@tie{}@code{3}. Calculations may be nested; the result of a function may
304 be used for another calculation.
312 These calculations are examples of evaluations; an expression like
313 @code{(* 3 4)} is replaced by its value @code{12}.
315 The same assignment can be done in completely in Scheme as well,
318 #(define twentyFour (* 2 twelve))
321 @c this next section is confusing -- need to rewrite
323 The @emph{name} of a variable is also an expression, similar to a
324 number or a string. It is entered as
331 @cindex quoting in Scheme
333 The quote mark @code{'} prevents the Scheme interpreter from substituting
334 @code{24} for the @code{twentyFour}. Instead, we get the name
337 @node Scheme procedures
338 @subsection Scheme procedures
340 @unnumberedsubsubsec Predicates
342 @unnumberedsubsubsec Return values
344 TODO -- write about scheme procedures
346 @node Scheme conditionals
347 @subsection Scheme conditionals
349 @unnumberedsubsubsec if
351 @unnumberedsubsubsec cond
354 @node Scheme in LilyPond
355 @section Scheme in LilyPond
359 * LilyPond Scheme syntax::
360 * LilyPond variables::
361 * Input variables and Scheme::
362 * Object properties::
363 * LilyPond compound variables::
364 * Internal music representation::
367 @node LilyPond Scheme syntax
368 @subsection LilyPond Scheme syntax
370 In a music file, snippets of Scheme code are introduced with the hash
371 mark @code{#}. So, the previous examples translated to LilyPond are
382 Note that LilyPond comments (@code{%} and @code{%@{ %@}}) cannot
383 be used within Scheme code. Comments in Guile Scheme are entered
387 ; this is a single-line comment
390 This a (non-nestable) Guile-style block comment
391 But these are rarely used by Schemers and never in
396 Multiple consecutive scheme expressions in a music file can be
397 combined using the @code{begin} operator. This permits the number
398 of hash marks to be reduced to one.
406 @c todo -- # introduces a scheme *expression*
407 @c need the concept of an expression
409 If @code{#} is followed by an opening parenthesis, @code{(}, as in
410 the example above, the parser will remain in Scheme mode until
411 a matching closing parenthesis, @code{)}, is found, so further
412 @code{#} symbols to introduce a Scheme section are not required.
414 For the rest of this section, we will assume that the data is entered
415 in a music file, so we add @code{#}s everywhere.
417 @node LilyPond variables
418 @subsection LilyPond variables
421 TODO -- make this read right
424 happens with variables. After defining a variable
431 variables can also be used in expressions, here
434 twentyFour = (* 2 twelve)
438 the number 24 is stored in the variable @code{twentyFour}.
440 @node Input variables and Scheme
441 @subsection Input variables and Scheme
443 The input format supports the notion of variables: in the following
444 example, a music expression is assigned to a variable with the name
448 traLaLa = @{ c'4 d'4 @}
453 There is also a form of scoping: in the following example, the
454 @code{\layout} block also contains a @code{traLaLa} variable, which is
455 independent of the outer @code{\traLaLa}.
457 traLaLa = @{ c'4 d'4 @}
458 \layout @{ traLaLa = 1.0 @}
461 In effect, each input file is a scope, and all @code{\header},
462 @code{\midi}, and @code{\layout} blocks are scopes nested inside that
465 Both variables and scoping are implemented in the GUILE module system.
466 An anonymous Scheme module is attached to each scope. An assignment of
469 traLaLa = @{ c'4 d'4 @}
473 is internally converted to a Scheme definition
475 (define traLaLa @var{Scheme value of `@code{... }'})
478 This means that input variables and Scheme variables may be freely
479 mixed. In the following example, a music fragment is stored in the
480 variable @code{traLaLa}, and duplicated using Scheme. The result is
481 imported in a @code{\score} block by means of a second variable
485 traLaLa = { c'4 d'4 }
487 %% dummy action to deal with parser lookahead
488 #(display "this needs to be here, sorry!")
490 #(define newLa (map ly:music-deep-copy
491 (list traLaLa traLaLa)))
493 (make-sequential-music newLa))
498 @c Due to parser lookahead
500 In this example, the assignment happens after the parser has
501 verified that nothing interesting happens after
502 @code{traLaLa = @{ ... @}}. Without the dummy statement in the
503 above example, the @code{newLa} definition is executed before
504 @code{traLaLa} is defined, leading to a syntax error.
506 The above example shows how to @q{export} music expressions from the
507 input to the Scheme interpreter. The opposite is also possible. By
508 wrapping a Scheme value in the function @code{ly:export}, a Scheme
509 value is interpreted as if it were entered in LilyPond syntax.
510 Instead of defining @code{\twice}, the example above could also have
515 @{ #(ly:export (make-sequential-music (list newLa))) @}
518 Scheme code is evaluated as soon as the parser encounters it. To
519 define some Scheme code in a macro (to be called later), use
520 @ref{Void functions}, or
524 (ly:set-option 'point-and-click #f))
533 Mixing Scheme and LilyPond variables is not possible with the
534 @code{--safe} option.
539 @node Object properties
540 @subsection Object properties
542 This syntax will be used very frequently, since many of the layout
543 tweaks involve assigning (Scheme) values to internal variables, for
547 \override Stem #'thickness = #2.6
550 This instruction adjusts the appearance of stems. The value @code{2.6}
551 is put into the @code{thickness} variable of a @code{Stem}
552 object. @code{thickness} is measured relative to the thickness of
553 staff lines, so these stem lines will be @code{2.6} times the
554 width of staff lines. This makes stems almost twice as thick as their
555 normal size. To distinguish between variables defined in input files (like
556 @code{twentyFour} in the example above) and variables of internal
557 objects, we will call the latter @q{properties} and the former
558 @q{variables.} So, the stem object has a @code{thickness} property,
559 while @code{twentyFour} is an variable.
561 @cindex properties vs. variables
562 @cindex variables vs. properties
564 @c todo -- here we're getting interesting. We're now introducing
565 @c LilyPond variable types. I think this deserves a section all
568 @node LilyPond compound variables
569 @subsection LilyPond compound variables
571 @unnumberedsubsubsec Offsets
573 Two-dimensional offsets (X and Y coordinates) as well as object sizes
574 (intervals with a left and right point) are entered as @code{pairs}. A
575 pair@footnote{In Scheme terminology, the pair is called @code{cons},
576 and its two elements are called @code{car} and @code{cdr} respectively.}
577 is entered as @code{(first . second)} and, like symbols, they must be quoted,
580 \override TextScript #'extra-offset = #'(1 . 2)
583 This assigns the pair (1, 2) to the @code{extra-offset} property of the
584 TextScript object. These numbers are measured in staff-spaces, so
585 this command moves the object 1 staff space to the right, and 2 spaces up.
587 @unnumberedsubsubsec Extents
589 todo -- write something about extents
591 @unnumberedsubsubsec Property alists
593 todo -- write something about property alists
595 @unnumberedsubsubsec Alist chains
597 todo -- write something about alist chains
599 @node Internal music representation
600 @subsection Internal music representation
602 When a music expression is parsed, it is converted into a set of
603 Scheme music objects. The defining property of a music object is that
604 it takes up time. Time is a rational number that measures the length
605 of a piece of music in whole notes.
607 A music object has three kinds of types:
610 music name: Each music expression has a name. For example, a note
611 leads to a @rinternals{NoteEvent}, and @code{\simultaneous} leads to
612 a @rinternals{SimultaneousMusic}. A list of all expressions
613 available is in the Internals Reference manual, under
614 @rinternals{Music expressions}.
617 @q{type} or interface: Each music name has several @q{types} or
618 interfaces, for example, a note is an @code{event}, but it is also a
619 @code{note-event}, a @code{rhythmic-event}, and a
620 @code{melodic-event}. All classes of music are listed in the
621 Internals Reference, under
622 @rinternals{Music classes}.
625 C++ object: Each music object is represented by an object of the C++
629 The actual information of a music expression is stored in properties.
630 For example, a @rinternals{NoteEvent} has @code{pitch} and
631 @code{duration} properties that store the pitch and duration of that
632 note. A list of all properties available can be found in the
633 Internals Reference, under @rinternals{Music properties}.
635 A compound music expression is a music object that contains other
636 music objects in its properties. A list of objects can be stored in
637 the @code{elements} property of a music object, or a single @q{child}
638 music object in the @code{element} property. For example,
639 @rinternals{SequentialMusic} has its children in @code{elements},
640 and @rinternals{GraceMusic} has its single argument in
641 @code{element}. The body of a repeat is stored in the @code{element}
642 property of @rinternals{RepeatedMusic}, and the alternatives in
645 @node Building complicated functions
646 @section Building complicated functions
648 This section explains how to gather the information necessary
649 to create complicated music functions.
652 * Displaying music expressions::
654 * Doubling a note with slurs (example)::
655 * Adding articulation to notes (example)::
659 @node Displaying music expressions
660 @subsection Displaying music expressions
662 @cindex internal storage
663 @cindex displaying music expressions
664 @cindex internal representation, displaying
666 @funindex \displayMusic
668 When writing a music function it is often instructive to inspect how
669 a music expression is stored internally. This can be done with the
670 music function @code{\displayMusic}
674 \displayMusic @{ c'4\f @}
691 (ly:make-duration 2 0 1 1)
693 (ly:make-pitch 0 0 0))
695 'AbsoluteDynamicEvent
700 By default, LilyPond will print these messages to the console along
701 with all the other messages. To split up these messages and save
702 the results of @code{\display@{STUFF@}}, redirect the output to
706 lilypond file.ly >display.txt
709 With a bit of reformatting, the above information is
713 (make-music 'SequentialMusic
714 'elements (list (make-music 'EventChord
715 'elements (list (make-music 'NoteEvent
716 'duration (ly:make-duration 2 0 1 1)
717 'pitch (ly:make-pitch 0 0 0))
718 (make-music 'AbsoluteDynamicEvent
722 A @code{@{ ... @}} music sequence has the name @code{SequentialMusic},
723 and its inner expressions are stored as a list in its @code{'elements}
724 property. A note is represented as an @code{EventChord} expression,
725 containing a @code{NoteEvent} object (storing the duration and
726 pitch properties) and any extra information (in this case, an
727 @code{AbsoluteDynamicEvent} with a @code{"f"} text property.
730 @node Music properties
731 @subsection Music properties
733 The @code{NoteEvent} object is the first object of the
734 @code{'elements} property of @code{someNote}.
738 \displayMusic \someNote
746 (ly:make-duration 2 0 1 1)
748 (ly:make-pitch 0 0 0))))
751 The @code{display-scheme-music} function is the function used by
752 @code{\displayMusic} to display the Scheme representation of a music
756 #(display-scheme-music (first (ly:music-property someNote 'elements)))
761 (ly:make-duration 2 0 1 1)
763 (ly:make-pitch 0 0 0))
766 Then the note pitch is accessed through the @code{'pitch} property
767 of the @code{NoteEvent} object,
770 #(display-scheme-music
771 (ly:music-property (first (ly:music-property someNote 'elements))
774 (ly:make-pitch 0 0 0)
777 The note pitch can be changed by setting this @code{'pitch} property,
779 @funindex \displayLilyMusic
782 #(set! (ly:music-property (first (ly:music-property someNote 'elements))
784 (ly:make-pitch 0 1 0)) ;; set the pitch to d'.
785 \displayLilyMusic \someNote
791 @node Doubling a note with slurs (example)
792 @subsection Doubling a note with slurs (example)
794 Suppose we want to create a function that translates input like
795 @code{a} into @code{a( a)}. We begin by examining the internal
796 representation of the desired result.
799 \displayMusic@{ a'( a') @}
810 (ly:make-duration 2 0 1 1)
812 (ly:make-pitch 0 5 0))
823 (ly:make-duration 2 0 1 1)
825 (ly:make-pitch 0 5 0))
832 The bad news is that the @code{SlurEvent} expressions
833 must be added @q{inside} the note (or more precisely,
834 inside the @code{EventChord} expression).
836 Now we examine the input,
848 (ly:make-duration 2 0 1 1)
850 (ly:make-pitch 0 5 0))))))
853 So in our function, we need to clone this expression (so that we
854 have two notes to build the sequence), add @code{SlurEvents} to the
855 @code{'elements} property of each one, and finally make a
856 @code{SequentialMusic} with the two @code{EventChords}.
859 doubleSlur = #(define-music-function (parser location note) (ly:music?)
860 "Return: @{ note ( note ) @}.
861 `note' is supposed to be an EventChord."
862 (let ((note2 (ly:music-deep-copy note)))
863 (set! (ly:music-property note 'elements)
864 (cons (make-music 'SlurEvent 'span-direction -1)
865 (ly:music-property note 'elements)))
866 (set! (ly:music-property note2 'elements)
867 (cons (make-music 'SlurEvent 'span-direction 1)
868 (ly:music-property note2 'elements)))
869 (make-music 'SequentialMusic 'elements (list note note2))))
873 @node Adding articulation to notes (example)
874 @subsection Adding articulation to notes (example)
876 The easy way to add articulation to notes is to merge two music
877 expressions into one context, as explained in
878 @ruser{Creating contexts}. However, suppose that we want to write
879 a music function that does this.
881 A @code{$variable} inside the @code{#@{...#@}} notation is like
882 a regular @code{\variable} in classical LilyPond notation. We
890 will not work in LilyPond. We could avoid this problem by attaching
891 the articulation to a fake note,
894 @{ << \music s1*0-.-> @}
898 but for the sake of this example, we will learn how to do this in
899 Scheme. We begin by examining our input and desired output,
911 (ly:make-duration 2 0 1 1)
913 (ly:make-pitch -1 0 0))))
924 (ly:make-duration 2 0 1 1)
926 (ly:make-pitch -1 0 0))
933 We see that a note (@code{c4}) is represented as an @code{EventChord}
934 expression, with a @code{NoteEvent} expression in its elements list. To
935 add a marcato articulation, an @code{ArticulationEvent} expression must
936 be added to the elements property of the @code{EventChord}
939 To build this function, we begin with
942 (define (add-marcato event-chord)
943 "Add a marcato ArticulationEvent to the elements of `event-chord',
944 which is supposed to be an EventChord expression."
945 (let ((result-event-chord (ly:music-deep-copy event-chord)))
946 (set! (ly:music-property result-event-chord 'elements)
947 (cons (make-music 'ArticulationEvent
948 'articulation-type "marcato")
949 (ly:music-property result-event-chord 'elements)))
953 The first line is the way to define a function in Scheme: the function
954 name is @code{add-marcato}, and has one variable called
955 @code{event-chord}. In Scheme, the type of variable is often clear
956 from its name. (this is good practice in other programming languages,
964 is a description of what the function does. This is not strictly
965 necessary, but just like clear variable names, it is good practice.
968 (let ((result-event-chord (ly:music-deep-copy event-chord)))
971 @code{let} is used to declare local variables. Here we use one local
972 variable, named @code{result-event-chord}, to which we give the value
973 @code{(ly:music-deep-copy event-chord)}. @code{ly:music-deep-copy} is
974 a function specific to LilyPond, like all functions prefixed by
975 @code{ly:}. It is use to make a copy of a music
976 expression. Here we copy @code{event-chord} (the parameter of the
977 function). Recall that our purpose is to add a marcato to an
978 @code{EventChord} expression. It is better to not modify the
979 @code{EventChord} which was given as an argument, because it may be
982 Now we have a @code{result-event-chord}, which is a
983 @code{NoteEventChord} expression and is a copy of
984 @code{event-chord}. We add the marcato to its @code{'elements}
988 (set! place new-value)
991 Here, what we want to set (the @q{place}) is the @code{'elements}
992 property of @code{result-event-chord} expression.
995 (ly:music-property result-event-chord 'elements)
998 @code{ly:music-property} is the function used to access music properties
999 (the @code{'elements}, @code{'duration}, @code{'pitch}, etc, that we
1000 see in the @code{\displayMusic} output above). The new value is the
1001 former @code{'elements} property, with an extra item: the
1002 @code{ArticulationEvent} expression, which we copy from the
1003 @code{\displayMusic} output,
1006 (cons (make-music 'ArticulationEvent
1007 'articulation-type "marcato")
1008 (ly:music-property result-event-chord 'elements))
1011 @code{cons} is used to add an element to a list without modifying
1012 the original list. This is what we want: the same list as before,
1013 plus the new @code{ArticulationEvent} expression. The order
1014 inside the @code{'elements} property is not important here.
1016 Finally, once we have added the marcato articulation to its @code{elements}
1017 property, we can return @code{result-event-chord}, hence the last line of
1020 Now we transform the @code{add-marcato} function into a music
1024 addMarcato = #(define-music-function (parser location event-chord)
1026 "Add a marcato ArticulationEvent to the elements of `event-chord',
1027 which is supposed to be an EventChord expression."
1028 (let ((result-event-chord (ly:music-deep-copy event-chord)))
1029 (set! (ly:music-property result-event-chord 'elements)
1030 (cons (make-music 'ArticulationEvent
1031 'articulation-type "marcato")
1032 (ly:music-property result-event-chord 'elements)))
1033 result-event-chord))
1036 We may verify that this music function works correctly,
1039 \displayMusic \addMarcato c4
1049 * Tweaking with Scheme::
1052 @c @node Tweaking with Scheme
1053 @c @section Tweaking with Scheme
1055 We have seen how LilyPond output can be heavily modified using
1057 @code{\override TextScript #'extra-offset = ( 1 . -1)}. But
1058 we have even more power if we use Scheme. For a full explanation
1059 of this, see the @ref{Scheme tutorial}, and
1060 @ref{Interfaces for programmers}.
1062 We can use Scheme to simply @code{\override} commands,
1064 TODO Find a simple example
1065 @c This isn't a valid example with skylining
1066 @c It works fine without padText -td
1070 @lilypond[quote,verbatim,ragged-right]
1071 padText = #(define-music-function (parser location padding) (number?)
1073 \once \override TextScript #'padding = #$padding
1077 c4^"piu mosso" b a b
1079 c4^"piu mosso" d e f
1081 c4^"piu mosso" fis a g
1087 We can use it to create new commands:
1089 @c Check this is a valid example with skylining
1090 @c It is - 'padding still works
1093 @lilypond[quote,verbatim,ragged-right]
1094 tempoPadded = #(define-music-function (parser location padding tempotext)
1097 \once \override Score.MetronomeMark #'padding = $padding
1098 \tempo \markup { \bold $tempotext }
1102 \tempo \markup { "Low tempo" }
1104 \tempoPadded #4.0 #"High tempo"
1110 Even music expressions can be passed in:
1112 @lilypond[quote,verbatim,ragged-right]
1113 pattern = #(define-music-function (parser location x y) (ly:music? ly:music?)
1120 \pattern {d16 dis} { ais16-> b\p }