]> git.donarmstrong.com Git - lilypond.git/blob - scm/framework-tex.scm
* scm/paper.scm (paper-alist): public.
[lilypond.git] / scm / framework-tex.scm
1 ;;;; framework-tex.scm --
2 ;;;;
3 ;;;;  source file of the GNU LilyPond music typesetter
4 ;;;;
5 ;;;; (c)  2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
6
7 (define-module (scm framework-tex)
8   #:export (output-framework-tex        
9             output-classic-framework-tex))
10
11 (use-modules (ice-9 regex)
12              (ice-9 string-fun)
13              (ice-9 format)
14              (guile)
15              (srfi srfi-13)
16              (lily))
17
18 ;; FIXME: rename
19 ;; what is bla supposed to do?  It breaks the default output terribly:
20
21 ;; \def\lilypondpaperbla$\backslash${$\backslash$}{bla$\backslash${$\backslash$}}%
22 ;; \lyitem{089.5557}{-15.3109}{\hbox{\magfontUGQLomTVo{}bla$\backslash${$\backslash$}}}%
23 ;; --jcn
24 (define-public (sanitize-tex-string s)
25   (if (ly:get-option 'safe)
26       (regexp-substitute/global
27        #f "\\\\"
28        (regexp-substitute/global #f "([{}])" "bla{}" 'pre  "\\" 1 'post )
29        'pre "$\\backslash$" 'post)
30       s))
31
32 (define (symbol->tex-key sym)
33   (regexp-substitute/global
34    #f "_" (sanitize-tex-string (symbol->string sym)) 'pre "X" 'post) )
35
36 (define (tex-number-def prefix key number)
37   (string-append
38    "\\def\\" prefix (symbol->tex-key key) "{" number "}%\n"))
39
40 (define-public (tex-font-command font)
41   (string-append
42    "magfont"
43    (string-encode-integer
44     (hashq (ly:font-filename font) 1000000))
45    "m"
46    (string-encode-integer
47     (inexact->exact (round (* 1000 (ly:font-magnification font)))))))
48
49 (define (font-load-command paper font)
50   (let* ((coding-alist (ly:font-encoding-alist font))
51          (font-encoding (assoc-get 'output-name coding-alist)))
52     (string-append
53      "\\font\\lilypond" (tex-font-command font) "="
54      (ly:font-filename font)
55      " scaled "
56      (ly:number->string (inexact->exact
57                          (round (* 1000
58                                    (ly:font-magnification font)
59                                    (ly:paper-outputscale paper)))))
60      "\n"
61      "\\def\\" (tex-font-command font) "{%\n"
62      ;; UGH.  Should be handled via alist.
63      (if (equal? "Extended-TeX-Font-Encoding---Latin" font-encoding)
64          "  \\lilypondfontencoding{T1}"
65          "  ")
66      "\\lilypond" (tex-font-command font)
67      "}%\n")))
68
69 (define (define-fonts paper)
70   (string-append
71    ;; UGH. FIXME.
72    "\\def\\lilypondpaperunit{mm}%\n"
73    (tex-number-def "lilypondpaper" 'outputscale
74                    (number->string (exact->inexact
75                                     (ly:paper-outputscale paper))))
76    (tex-string-def "lilypondpaper" 'papersize
77                    (eval 'papersizename (ly:output-def-scope paper)))
78    ;; paper/layout?
79    (tex-string-def "lilypondpaper" 'inputencoding
80                    (eval 'inputencoding (ly:output-def-scope paper)))
81
82    (apply string-append
83           (map (lambda (x) (font-load-command paper x))
84                (ly:paper-fonts paper)))))
85
86 (define (header-to-file fn key val)
87   (set! key (symbol->string key))
88   (if (not (equal? "-" fn))
89       (set! fn (string-append fn "." key)))
90   (display
91    (format (_ "Writing header field `~a' to `~a'...")
92            key
93            (if (equal? "-" fn) "<stdout>" fn))
94    (current-error-port))
95   (if (equal? fn "-")
96       (display val)
97       (display val (open-file fn "w")))
98   (newline (current-error-port))
99   "")
100
101 (define (output-scopes scopes fields basename)
102   (define (output-scope scope)
103     (apply
104      string-append
105      (module-map
106       (lambda (sym var)
107         (let ((val (if (variable-bound? var) (variable-ref var) "")))
108           (if (and (memq sym fields) (string? val))
109               (header-to-file basename sym val))
110           ""))
111       scope)))
112   (apply string-append (map output-scope scopes)))
113
114 (define (tex-string-def prefix key str)
115   (if (equal? "" (sans-surrounding-whitespace (sanitize-tex-string str)))
116       (string-append "\\let\\" prefix (symbol->tex-key key) "\\undefined%\n")
117       (string-append "\\def\\" prefix (symbol->tex-key key)
118                      "{" (sanitize-tex-string str) "}%\n")))
119
120 (define (header paper page-count classic?)
121   (let ((scale (ly:output-def-lookup paper 'outputscale))
122         (texpaper (string-append
123                    (ly:output-def-lookup paper 'papersizename)
124                    "paper"))
125         (landscape? (eq? #t (ly:output-def-lookup paper 'landscape))))
126     (string-append
127      "% Generated by LilyPond "
128      (lilypond-version) "\n"
129      "% at " "time-stamp,FIXME" "\n"
130      (if classic?
131          (tex-string-def "lilypond" 'classic "1")
132          "")
133
134      (if (ly:get-option 'safe)
135          "\\nofiles\n"
136          "")
137
138      (tex-string-def
139       "lilypondpaper" 'linewidth
140       (ly:number->string (* scale (ly:output-def-lookup paper 'linewidth))))
141      "\\def\\lilyponddocumentclassoptions{"
142      texpaper
143      (if landscape? ",landscape" "")
144      "}%\n"
145      (tex-string-def
146       "lilypondpaper" 'interscoreline
147       (ly:number->string
148        (* scale (ly:output-def-lookup paper 'interscoreline)))))))
149
150 (define (header-end)
151   (string-append
152    "\\def\\scaletounit{ "
153    (number->string (cond
154                     ((equal? (ly:unit) "mm") (/ 72.0 25.4))
155                     ((equal? (ly:unit) "pt") (/ 72.0 72.27))
156                     (else (error "unknown unit" (ly:unit)))))
157    " mul }%\n"
158    "\\ifx\\lilypondstart\\undefined\n"
159    "  \\input lilyponddefs\n"
160    "\\fi\n"
161    "\\lilypondstart\n"
162    "\\lilypondspecial\n"
163    "\\lilypondpostscript\n"))
164
165 (define (dump-page putter page last? with-extents?)
166   (ly:outputter-dump-string
167    putter
168    (format "\\lybox{~a}{~a}{%\n"
169            (if with-extents?
170                (interval-start (ly:stencil-extent page X))
171                0.0)
172            (if with-extents?
173                (- (interval-start (ly:stencil-extent page Y)))
174                0.0)))
175   (ly:outputter-dump-stencil putter page)
176   (ly:outputter-dump-string
177    putter
178    (if last?
179        "}%\n\\vfill\n"
180        "}%\n\\vfill\n\\lilypondpagebreak\n")))
181
182 (define-public (output-framework outputter book scopes fields basename )
183   (let* ((paper (ly:paper-book-paper book))
184          (pages (ly:paper-book-pages book))
185          (last-page (car (last-pair pages)))
186          (with-extents
187           (eq? #t (ly:output-def-lookup paper 'dump-extents))))
188     (for-each
189      (lambda (x)
190        (ly:outputter-dump-string outputter x))
191      (list
192       (header paper (length pages) #f)
193       (define-fonts paper)
194       (header-end)))
195     (ly:outputter-dump-string outputter "\\lilypondnopagebreak\n")
196     (for-each
197      (lambda (page)
198        (dump-page outputter page (eq? last-page page) with-extents))
199      pages)
200     (ly:outputter-dump-string outputter "\\lilypondend\n")))
201
202 (define (dump-line putter line last?)
203   (ly:outputter-dump-string
204    putter
205    (format "\\lybox{~a}{~a}{%\n"
206            (ly:number->string
207             (max 0 (interval-end (ly:paper-system-extent line X))))
208            (ly:number->string
209             (interval-length (ly:paper-system-extent line Y)))))
210
211   (ly:outputter-dump-stencil putter (ly:paper-system-stencil line))
212   (ly:outputter-dump-string
213    putter
214    (if last?
215        "}%\n"
216        "}\\interscoreline\n")))
217
218 (define-public (output-classic-framework
219                 outputter book scopes fields basename)
220   (let* ((paper (ly:paper-book-paper book))
221          (lines (ly:paper-book-systems book))
222          (last-line (car (last-pair lines))))
223     (for-each
224      (lambda (x)
225        (ly:outputter-dump-string outputter x))
226      (list
227       ;;FIXME
228       (header paper (length lines) #f)
229       "\\def\\lilypondclassic{1}%\n"
230       (output-scopes scopes fields basename)
231       (define-fonts paper)
232       (header-end)))
233
234     (for-each
235      (lambda (line) (dump-line outputter line (eq? line last-line))) lines)
236     (ly:outputter-dump-string outputter "\\lilypondend\n")))
237
238 (define-public (output-preview-framework
239                 outputter book scopes fields basename )
240   (let* ((paper (ly:paper-book-paper book))
241          (lines (ly:paper-book-systems book)))
242     (for-each
243      (lambda (x)
244        (ly:outputter-dump-string outputter x))
245      (list
246       ;;FIXME
247       (header paper (length lines) #f)
248       "\\def\\lilypondclassic{1}%\n"
249       (output-scopes scopes fields basename)
250       (define-fonts paper)
251       (header-end)))
252
253     (dump-line outputter (car lines) #t)
254     (ly:outputter-dump-string outputter "\\lilypondend\n")))
255
256 (define-public (convert-to-pdf book name)
257   (let* ((defs (ly:paper-book-paper book))
258          (papersizename (ly:output-def-lookup defs 'papersizename)))
259     (postscript->pdf (if (string? papersizename) papersizename "a4")
260                      (string-append
261                       (basename name ".tex")
262                       ".ps"))))
263
264 (define-public (convert-to-png book name)
265   (let* ((defs (ly:paper-book-paper book))
266          (resolution (ly:output-def-lookup defs 'pngresolution)))
267     (postscript->png
268      (if (number? resolution)
269          resolution
270          (ly:get-option 'resolution))
271      (string-append (basename name ".tex") ".ps"))))
272
273
274 ;;
275 ;; ugh  -   double check this. We are leaking
276 ;; untrusted (user-settable) info to a command-line 
277 ;;
278 (define-public (convert-to-ps book name)
279   (let* ((paper (ly:paper-book-paper book))
280          (preview? (string-contains name ".preview"))
281          (papersizename (ly:output-def-lookup paper 'papersizename))
282          (landscape? (eq? #t (ly:output-def-lookup paper 'landscape)))
283          (base (basename name ".tex"))
284          (cmd (string-append "dvips "
285                              (if preview?
286                                  " -E "
287                                  (if (member papersizename
288                                              (map car paper-alist))
289                                      (string-append "-t " papersizename)
290                                      ""))
291                              (if landscape?
292                                  " -t landscape "
293                                  " ")
294                              "  -u+ec-mftrace.map -u+lilypond.map -Ppdf "
295                              base)))
296
297     (if (not (ly:get-option 'verbose))
298         (begin
299           (format (current-error-port) (_ "Converting to `~a.ps'...") base)
300           (newline (current-error-port))))
301     (ly:system cmd)))
302
303 (define-public (convert-to-dvi book name)
304   (let* ((curr-extra-mem
305           (string->number
306            (regexp-substitute/global
307             #f " *%.*\n?"
308             (ly:kpathsea-expand-variable "$extra_mem_top")
309             'pre "" 'post)))
310          (base (basename name ".tex"))
311          (cmd (string-append
312                "latex \\\\nonstopmode \\\\input " name
313                )))
314     (setenv "extra_mem_top" (number->string (max curr-extra-mem 1024000)))
315     (if (not (ly:get-option 'verbose))
316         (begin
317           (format (current-error-port) (_ "Converting to `~a.dvi'...") base)
318           (newline (current-error-port))))
319
320     ;; fixme: set in environment?
321     (if (ly:get-option 'safe)
322         (set! cmd (string-append "openout_any=p " cmd)))
323
324     (ly:system cmd)))
325
326 (define-public (convert-to-tex book name)
327   #t)