]> git.donarmstrong.com Git - lilypond.git/blob - scm/framework-tex.scm
* mf/GNUmakefile: remove SAUTER_FONTS.
[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-1)
16              (srfi srfi-13)
17              (lily))
18
19 (define-public (sanitize-tex-string s)
20   (if (ly:get-option 'safe)
21       (regexp-substitute/global
22        #f "\\\\"
23        (regexp-substitute/global #f "([{}])" s 'pre  "\\" 1 'post )
24        'pre "$\\backslash$" 'post)
25       s))
26
27 (define (symbol->tex-key sym)
28   (regexp-substitute/global
29    #f "_" (sanitize-tex-string (symbol->string sym)) 'pre "X" 'post) )
30
31 (define (tex-number-def prefix key number)
32   (string-append
33    "\\def\\" prefix (symbol->tex-key key) "{" number "}%\n"))
34
35 (define-public (digits->letters str)
36   (regexp-substitute/global
37    #f "[-\\._]"
38    (regexp-substitute/global
39     #f "([0-9])" str
40     'pre
41     (lambda (match)
42       (make-string
43        1
44        (integer->char
45         (+ (char->integer #\A)
46            (- (char->integer #\0))
47            (char->integer (string-ref (match:substring match 1) 0)))
48         )))
49     'post)
50    'pre ""
51    'post))
52
53 (define-public (tex-font-command-raw name magnification)
54   (string-append
55    "magfont"
56    (digits->letters (format "~a" name))
57    "m"
58    (string-encode-integer
59     (inexact->exact (round (* 1000 magnification))))))
60
61 (define-public (tex-font-command font)
62   (tex-font-command-raw
63    (ly:font-file-name font) (ly:font-magnification font)))
64
65 (define (otf-font-load-command paper font)
66   (let* ((sub-fonts (ly:font-sub-fonts font)))
67     (string-append
68      (apply string-append
69             (map
70              (lambda (sub-name)
71                (format #f "\\font\\~a=~a scaled ~a%\n"
72                        (tex-font-command-raw
73                         sub-name (ly:font-magnification font))
74                        sub-name
75                        (ly:number->string
76                         (inexact->exact
77                          (round (* 1000
78                                    (ly:font-magnification font)
79                                    (ly:paper-outputscale paper)))))))
80              sub-fonts)))))
81
82 (define (simple-font-load-command paper font)
83   (let* ((coding-alist (ly:font-encoding-alist font))
84          (font-encoding (assoc-get 'output-name coding-alist)))
85     (string-append
86      "\\font\\lilypond" (tex-font-command font) "="
87      (if (or (equal? (ly:font-encoding font) "cork-lm")
88              ;; FIXME: encoding: FontSpecific for cork-lm
89              (string-prefix? "lm" (ly:font-file-name font)))
90          "cork-" "")
91      (ly:font-file-name font)
92      " scaled "
93      (ly:number->string (inexact->exact
94                          (round (* 1000
95                                    (ly:font-magnification font)
96                                    (ly:paper-outputscale paper)))))
97      "\n"
98      "\\def\\" (tex-font-command font) "{%\n"
99      ;; UGH.  Should be handled via alist.
100      (if (or (equal? "Extended-TeX-Font-Encoding---Latin" font-encoding)
101              (not font-encoding))
102          "  \\lilypondfontencoding{T1}"
103          "  ")
104      "\\lilypond" (tex-font-command font)
105      "}%\n")))
106
107 (define (font-load-command paper font)
108   (if (pair? (ly:font-sub-fonts font))
109       (otf-font-load-command paper font)
110       (simple-font-load-command paper font)))
111
112 (define (define-fonts paper)
113   (string-append
114    ;; UGH. FIXME.
115    "\\def\\lilypondpaperunit{mm}%\n"
116    (tex-number-def "lilypondpaper" 'outputscale
117                    (number->string (exact->inexact
118                                     (ly:paper-outputscale paper))))
119    (tex-string-def "lilypondpaper" 'papersize
120                    (eval 'papersizename (ly:output-def-scope paper)))
121    ;; paper/layout?
122    (tex-string-def "lilypondpaper" 'inputencoding
123                    (eval 'inputencoding (ly:output-def-scope paper)))
124
125    (apply string-append
126           (map (lambda (x) (font-load-command paper x))
127                (ly:paper-fonts paper)))))
128
129 (define (header-to-file fn key val)
130   (set! key (symbol->string key))
131   (if (not (equal? "-" fn))
132       (set! fn (string-append fn "." key)))
133   (display
134    (format (_ "Writing header field `~a' to `~a'...")
135            key
136            (if (equal? "-" fn) "<stdout>" fn))
137    (current-error-port))
138   (if (equal? fn "-")
139       (display val)
140       (display val (open-file fn "w")))
141   (newline (current-error-port))
142   "")
143
144 (define (output-scopes scopes fields basename)
145   (define (output-scope scope)
146     (apply
147      string-append
148      (module-map
149       (lambda (sym var)
150         (let ((val (if (variable-bound? var) (variable-ref var) "")))
151           (if (and (memq sym fields) (string? val))
152               (header-to-file basename sym val))
153           ""))
154       scope)))
155   (apply string-append (map output-scope scopes)))
156
157 (define (tex-string-def prefix key str)
158   (if (equal? "" (sans-surrounding-whitespace (sanitize-tex-string str)))
159       (string-append "\\let\\" prefix (symbol->tex-key key) "\\undefined%\n")
160       (string-append "\\def\\" prefix (symbol->tex-key key)
161                      "{" (sanitize-tex-string str) "}%\n")))
162
163 (define (header paper page-count classic?)
164   (let ((scale (ly:output-def-lookup paper 'outputscale))
165         (texpaper (string-append
166                    (ly:output-def-lookup paper 'papersizename)
167                    "paper"))
168         (landscape? (eq? #t (ly:output-def-lookup paper 'landscape))))
169     (string-append
170      "% Generated by LilyPond "
171      (lilypond-version) "\n"
172      "% at " "time-stamp,FIXME" "\n"
173      (if classic?
174          (tex-string-def "lilypond" 'classic "1")
175          "")
176
177      (if (ly:get-option 'safe)
178          "\\nofiles\n"
179          "")
180
181      (tex-string-def
182       "lilypondpaper" 'linewidth
183       (ly:number->string (* scale (ly:output-def-lookup paper 'linewidth))))
184      "\\def\\lilyponddocumentclassoptions{"
185      (sanitize-tex-string texpaper)
186      (if landscape? ",landscape" "")
187      "}%\n"
188      (tex-string-def
189       "lilypondpaper" 'interscoreline
190       (ly:number->string
191        (* scale (ly:output-def-lookup paper 'interscoreline)))))))
192
193 (define (header-end)
194   (string-append
195    "\\def\\scaletounit{ "
196    (number->string (cond
197                     ((equal? (ly:unit) "mm") (/ 72.0 25.4))
198                     ((equal? (ly:unit) "pt") (/ 72.0 72.27))
199                     (else (error "unknown unit" (ly:unit)))))
200    " mul }%\n"
201    "\\ifx\\lilypondstart\\undefined\n"
202    "  \\input lilyponddefs\n"
203    "\\fi\n"
204    "\\lilypondstart\n"
205    "\\lilypondspecial\n"
206    "\\lilypondpostscript\n"))
207
208 (define (dump-page putter page last? with-extents?)
209   (ly:outputter-dump-string
210    putter
211    (format "\\lybox{~a}{~a}{%\n"
212            (if with-extents?
213                (interval-start (ly:stencil-extent page X))
214                0.0)
215            (if with-extents?
216                (- (interval-start (ly:stencil-extent page Y)))
217                0.0)))
218   (ly:outputter-dump-stencil putter page)
219   (ly:outputter-dump-string
220    putter
221    (if last?
222        "}%\n\\vfill\n"
223        "}%\n\\vfill\n\\lilypondpagebreak\n")))
224
225 (define-public (output-framework outputter book scopes fields basename )
226   (let* ((paper (ly:paper-book-paper book))
227          (pages (ly:paper-book-pages book))
228          (last-page (car (last-pair pages)))
229          (with-extents
230           (eq? #t (ly:output-def-lookup paper 'dump-extents))))
231     (for-each
232      (lambda (x)
233        (ly:outputter-dump-string outputter x))
234      (list
235       (header paper (length pages) #f)
236       (define-fonts paper)
237       (header-end)))
238     (ly:outputter-dump-string outputter "\\lilypondnopagebreak\n")
239     (for-each
240      (lambda (page)
241        (dump-page outputter page (eq? last-page page) with-extents))
242      pages)
243     (ly:outputter-dump-string outputter "\\lilypondend\n")))
244
245 (define (dump-line putter line last?)
246   (ly:outputter-dump-string
247    putter
248    (format "\\lybox{~a}{~a}{%\n"
249            (ly:number->string
250             (max 0 (interval-end (ly:paper-system-extent line X))))
251            (ly:number->string
252             (interval-length (ly:paper-system-extent line Y)))))
253
254   (ly:outputter-dump-stencil putter (ly:paper-system-stencil line))
255   (ly:outputter-dump-string
256    putter
257    (if last?
258        "}%\n"
259        "}\\interscoreline\n")))
260
261 (define-public (output-classic-framework
262                 outputter book scopes fields basename)
263   (let* ((paper (ly:paper-book-paper book))
264          (lines (ly:paper-book-systems book))
265          (last-line (car (last-pair lines))))
266     (for-each
267      (lambda (x)
268        (ly:outputter-dump-string outputter x))
269      (list
270       ;;FIXME
271       (header paper (length lines) #f)
272       "\\def\\lilypondclassic{1}%\n"
273       (output-scopes scopes fields basename)
274       (define-fonts paper)
275       (header-end)))
276
277     (for-each
278      (lambda (line) (dump-line outputter line (eq? line last-line))) lines)
279     (ly:outputter-dump-string outputter "\\lilypondend\n")))
280
281 (define-public (output-preview-framework
282                 outputter book scopes fields basename )
283   (let* ((paper (ly:paper-book-paper book))
284          (lines (ly:paper-book-systems book))
285          (first-notes-index (list-index
286                              (lambda (s) (not (ly:paper-system-title? s)))
287                              lines)))
288
289     (for-each
290      (lambda (x)
291        (ly:outputter-dump-string outputter x))
292      (list
293       
294       ;;FIXME
295       (header paper (length lines) #f)
296       "\\def\\lilypondclassic{1}%\n"
297       (output-scopes scopes fields basename)
298       (define-fonts paper)
299       (header-end)))
300
301     (for-each
302      (lambda (l)
303        (dump-line outputter l (not (ly:paper-system-title? l))))
304      (take lines (1+ first-notes-index)))
305     (ly:outputter-dump-string outputter "\\lilypondend\n")))
306
307 (define-public (convert-to-pdf book name)
308   (let* ((defs (ly:paper-book-paper book))
309          (papersizename (ly:output-def-lookup defs 'papersizename)))
310     (postscript->pdf (if (string? papersizename) papersizename "a4")
311                      (string-append
312                       (basename name ".tex")
313                       ".ps"))))
314
315 (define-public (convert-to-png book name)
316   (let* ((defs (ly:paper-book-paper book))
317          (resolution (ly:output-def-lookup defs 'pngresolution)))
318     (postscript->png
319      (if (number? resolution)
320          resolution
321          (ly:get-option 'resolution))
322      (string-append (basename name ".tex") ".ps"))))
323
324 (define-public (convert-to-ps book name)
325   (let* ((paper (ly:paper-book-paper book))
326          (preview? (string-contains name ".preview"))
327
328          (papersizename (ly:output-def-lookup paper 'papersizename))
329          (landscape? (eq? #t (ly:output-def-lookup paper 'landscape)))
330          (base (basename name ".tex"))
331          (cmd (string-append "dvips "
332                              (if preview?
333                                  "-E "
334                                  (string-append
335                                   "-t"
336                                   ;; careful: papersizename is user-set.
337                                   (sanitize-command-option papersizename)
338                                   " "))
339                              (if landscape? "-t landscape " "")
340                              (if (ly:kpathsea-find-file "lm.map")
341                                  "-u+lm.map " "")
342                              (if (ly:kpathsea-find-file "ecrm10.pfa")
343                                  "-u+ec-mftrace.map " "")
344                              "-u+lilypond.map -Ppdf " ""
345                              base)))
346     (let ((ps-name (string-append base ".ps")))
347       (if (access? ps-name W_OK)
348           (delete-file ps-name)))
349     (if (not (ly:get-option 'verbose))
350         (begin
351           (format (current-error-port) (_ "Converting to `~a.ps'...") base)
352           (newline (current-error-port))))
353     (ly:system cmd)))
354
355 (define-public (convert-to-dvi book name)
356   (let* ((curr-extra-mem
357           (string->number
358            (regexp-substitute/global
359             #f " *%.*\n?"
360             (ly:kpathsea-expand-variable "$extra_mem_top")
361             'pre "" 'post)))
362          (base (basename name ".tex"))
363          (cmd (string-append
364                "latex \\\\nonstopmode \\\\input " name)))
365     (setenv "extra_mem_top" (number->string (max curr-extra-mem 1024000)))
366     (let ((dvi-name (string-append base ".dvi")))
367       (if (access? dvi-name W_OK)
368           (delete-file dvi-name)))
369     (if (not (ly:get-option 'verbose))
370         (begin
371           (format (current-error-port) (_ "Converting to `~a.dvi'...") base)
372           (newline (current-error-port))))
373
374     ;; fixme: set in environment?
375     (if (ly:get-option 'safe)
376         (set! cmd (string-append "openout_any=p " cmd)))
377
378     (ly:system cmd)))
379
380 (define-public (convert-to-tex book name)
381   #t)