]> git.donarmstrong.com Git - lilypond.git/blob - scm/framework-tex.scm
(convert-to-dvi): redirect output to
[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    (string-append "\\lybox{"
206                   (ly:number->string
207                    (interval-length (ly:paper-system-extent line X)))
208                   "}{"
209                   (ly:number->string
210                    (interval-length (ly:paper-system-extent line Y)))
211                   "}{%\n"))
212
213   (ly:outputter-dump-stencil putter (ly:paper-system-stencil line))
214   (ly:outputter-dump-string
215    putter
216    (if last?
217        "}%\n"
218        "}\\interscoreline\n")))
219
220 (define-public (output-classic-framework
221                 outputter book scopes fields basename)
222   (let* ((paper (ly:paper-book-paper book))
223          (lines (ly:paper-book-systems book))
224          (last-line (car (last-pair lines))))
225     (for-each
226      (lambda (x)
227        (ly:outputter-dump-string outputter x))
228      (list
229       ;;FIXME
230       (header paper (length lines) #f)
231       "\\def\\lilypondclassic{1}%\n"
232       (output-scopes scopes fields basename)
233       (define-fonts paper)
234       (header-end)))
235
236     (for-each
237      (lambda (line) (dump-line outputter line (eq? line last-line))) lines)
238     (ly:outputter-dump-string outputter "\\lilypondend\n")))
239
240 (define-public (output-preview-framework
241                 outputter book scopes fields basename )
242   (let* ((paper (ly:paper-book-paper book))
243          (lines (ly:paper-book-systems book)))
244     (for-each
245      (lambda (x)
246        (ly:outputter-dump-string outputter x))
247      (list
248       ;;FIXME
249       (header paper (length lines) #f)
250       "\\def\\lilypondclassic{1}%\n"
251       (output-scopes scopes fields basename)
252       (define-fonts paper)
253       (header-end)))
254
255     (dump-line outputter (car lines) #t)
256     (ly:outputter-dump-string outputter "\\lilypondend\n")))
257
258 (define-public (convert-to-pdf book name)
259   (let* ((defs (ly:paper-book-paper book))
260          (papersizename (ly:output-def-lookup defs 'papersizename)))
261     (postscript->pdf (if (string? papersizename) papersizename "a4")
262                      (string-append
263                       (basename name ".tex")
264                       ".ps"))))
265
266 (define-public (convert-to-png book name)
267   (let* ((defs (ly:paper-book-paper book))
268          (resolution (ly:output-def-lookup defs 'pngresolution)))
269     (postscript->png
270      (if (number? resolution) resolution 90)
271      (string-append (basename name ".tex") ".ps"))))
272
273 (define-public (convert-to-ps book name)
274   (let* ((paper (ly:paper-book-paper book))
275          (preview? (string-contains name ".preview"))
276          (papersizename (ly:output-def-lookup paper 'papersizename))
277          (landscape? (eq? #t (ly:output-def-lookup paper 'landscape)))
278          (base (basename name ".tex"))
279          (cmd (string-append "dvips "
280                              (if preview?
281                                  " -E "
282                                  (string-append " -t " papersizename))
283                              (if landscape?
284                                  " -t landscape "
285                                  " ")
286                              "  -u+ec-mftrace.map -u+lilypond.map -Ppdf "
287                              base
288
289                              (if (ly:get-option 'verbose)
290                                  " "
291                                  " 2>&1 1>& /dev/null ")
292                              )))
293
294     (if (ly:get-option 'verbose)
295         (begin 
296           (newline (current-error-port))
297
298           (display (format #f (_ "Invoking ~S") cmd) (current-error-port))
299           (newline (current-error-port)))
300         (display (format #f "Converting to `~a.ps'...\n" base) (current-error-port))
301         )
302     (system cmd)))
303
304 (define-public (convert-to-dvi book name)
305   (let* ((curr-extra-mem
306           (string->number
307            (regexp-substitute/global
308             #f " *%.*\n?"
309             (ly:kpathsea-expand-variable "$extra_mem_top")
310             'pre "" 'post)))
311          (base (basename name ".tex"))
312          (cmd (string-append
313                "latex \\\\nonstopmode \\\\input " name
314                (if (ly:get-option 'verbose)
315                    " "
316                    " 2>&1 1>& /dev/null ")
317
318                )))
319     (setenv "extra_mem_top" (number->string (max curr-extra-mem 1024000)))
320     (if (ly:get-option 'verbose)
321         (begin 
322           (newline (current-error-port))
323           (display (format #f (_ "Invoking ~S") cmd) (current-error-port))
324           (newline (current-error-port)))
325         (format (current-error-port) "Converting to `~a.dvi'...\n" base))
326
327     ;; fixme: set in environment?
328     (if (ly:get-option 'safe)
329         (set! cmd (string-append "openout_any=p " cmd)))
330
331     (system cmd)))
332
333 (define-public (convert-to-tex book name)
334   #t)