Attachment 'AbcMusic.py'
Download 1 """
2 MoinMoin - Processor for abc format music syntax using abc2ps
3
4 Copyright (c) 2004 by Nathan Whitehead <nwhitehe@cs.ucsc.edu>
5 All rights reserved, see COPYING for details.
6 """
7
8 import string, sys, os, re, sha
9 from MoinMoin import config
10
11 # Set these according to local environment
12 config_cache_dir='/cse/grads/nwhitehe/.html/wiki/abcps'
13 config_cache_url=config.url_prefix+'abcps'
14 config_tmp_dir='/tmp'
15 config_external_abc2ps='/cse/grads/nwhitehe/bin/abcm2ps'
16 config_external_pstopnm='/usr/local/bin/pstopnm'
17 config_external_gs='/usr/local/gnu/bin/gs'
18 config_external_pnmcat='/usr/local/bin/pnmcat'
19 config_external_pnmcrop='/usr/local/bin/pnmcrop'
20 config_external_abc2midi='/cse/grads/nwhitehe/bin/abc2midi'
21
22 # Use png or gif?
23 config_use_gif=1
24 config_external_rasterize='/usr/local/bin/ppmtogif'
25 config_external_gzip='/usr/local/gnu/bin/gzip'
26 config_score_orientation='-tb' # or -lr for horizontal
27 # Serve and store scores gzipped to save space?
28 config_zip_scores=0
29
30 # Cut off hash to this many characters for user friendliness
31 hash_length = 6
32 # Show code in HTML page by default?
33 show_code = 1
34 # Generate PNG graphics of each page? (slow and memory intensive for server)
35 show_score = 1
36 # Show an embedded MIDI controller for playing the song?
37 show_midi = 1
38 # Syntax highlighting colors for ABC code
39 header_color = '#6000a0'
40 info_color = '#006000'
41 note_color = '#000000'
42 bar_color = '#ff0000'
43 continues_color = '#ff00ff'
44 comment_color = '#ff5050'
45 chord_color = '#808080'
46
47 def quote_apply(f, txt):
48 """Apply a given function on text to all quotations in a string"""
49 # This is harder than it sounds because replacement text may have quotes
50 qi = txt.find('"')
51 while not qi == -1:
52 qi2 = txt.find('"', qi + 1)
53 if not qi2 == -1:
54 newtext = f(txt[qi:qi2 + 1])
55 txt = txt[:qi] + newtext + txt[qi2 + 1:]
56 lenincr = len(newtext) - (qi2 - qi)
57 qi = txt.find('"', qi2 + lenincr)
58 else:
59 qi = -1
60 return txt
61
62 def color_txt(c, txt):
63 """Make text appear the given ascii color"""
64 return '<font color="' + c + '">' + txt + '</font>'
65
66 def colorize_line(txt):
67 # If it is header, color it and we're done
68 if len(txt) >= 2 and txt[1] == ':':
69 return color_txt(header_color, txt[:2]) + color_txt(info_color, txt[2:])
70 # If it is comment, color and we're done
71 if len(txt) >= 1 and txt[0] == '%':
72 return color_txt(comment_color, txt)
73 # Color quotations (chords) first, otherwise
74 # we will get more quotes from font tags later.
75 def give_chord_color(txt):
76 return color_txt(chord_color, txt)
77 txt = quote_apply(give_chord_color, txt)
78 txt = txt.replace('|', color_txt(bar_color, '|'))
79 txt = txt.replace('\\', color_txt(continues_color, '\\'))
80 return color_txt(note_color, txt)
81
82 def colorize(lines):
83 """Do rudimentary syntax highlighting of ABC music in HTML"""
84 # Do it line by line
85 clines = map(colorize_line, lines)
86 return string.join(clines, '\n')
87
88 def get_title(lines):
89 """Return the title string, if it exists"""
90 for l in lines:
91 if len(l) >= 2 and l[0] == 'T' and l[1] == ':':
92 return l[2:]
93 return "(Untitled)"
94
95 def cleanup(txt):
96 """Scrub a title so it may be used in a filename"""
97 # Old way, txt.replace(' ', '_').replace('(', '').replace(')', '')
98 res = ""
99 for x in txt:
100 if x.isalnum():
101 res = res + x
102 if x == ' ':
103 res = res + '_'
104 return res
105
106 def process_arguments(lines):
107 global show_code
108 global show_score
109 if len(lines) > 0:
110 stripline0 = string.strip(lines[0])
111 if stripline0 == "#!AbcMusic":
112 del lines[0]
113 process_arguments(lines)
114 if stripline0 == "#show-code-off":
115 del lines[0]
116 show_code = 0
117 process_arguments(lines)
118 if stripline0 == "#show-code-on":
119 del lines[0]
120 show_code = 1
121 process_arguments(lines)
122 if stripline0 == "#show-score-off":
123 del lines[0]
124 show_score = 0
125 process_arguments(lines)
126 if stripline0 == "#show-score-on":
127 del lines[0]
128 show_score = 1
129 process_arguments(lines)
130 return
131
132 def process(request, formatter, lines):
133 global show_code
134 # Preprocessing stage
135 process_arguments(lines)
136 title = get_title(lines)
137 texstr = string.join(lines, '\n')
138 texstr = string.strip(texstr)
139 hash = sha.new(texstr).hexdigest()[:hash_length]
140 name = cleanup(title) + '_' + hash
141
142 filepath = "%s/%s" % (config_cache_dir, name)
143 urlpath = "%s/%s" % (config_cache_url, name)
144
145 if config_use_gif:
146 suffix = ".gif"
147 else:
148 suffix = ".png"
149 abcpath = filepath + ".abc"
150 pspath = filepath + ".ps"
151 psgzpath = filepath + ".ps.gz"
152 pngpath = filepath + suffix
153 logpath = filepath + ".log"
154 midipath = filepath + ".mid"
155 abcurl = urlpath + ".abc"
156 if config_zip_scores:
157 psurl = urlpath + ".ps.gz"
158 else:
159 psurl = urlpath + ".ps"
160 pngurl = urlpath + suffix
161 logurl = urlpath + ".log"
162 midiurl = urlpath + ".mid"
163
164 # Delete logfile
165 os.system("rm -f %s" % logpath)
166
167 # Generate PS
168 if not os.path.exists(pspath):
169 data = open(abcpath, "w")
170 data.write('%s' % texstr)
171 data.close()
172
173 options = "-e 1"
174 cmd = "cd %(workingdir)s ; %(abc2ps)s %(options)s -O %(outfile)s %(infile)s >> %(logfile)s 2>&1" % {
175 "workingdir" : config_tmp_dir,
176 "abc2ps": config_external_abc2ps,
177 "options": options,
178 "outfile" : pspath,
179 "infile": abcpath,
180 "logfile": logpath
181 }
182 os.system(cmd)
183 os.system("chmod 644 " + pspath)
184 os.system("chmod 644 " + abcpath)
185 if config_zip_scores:
186 cmd = "%(gzip)s %(file)s 2> /dev/null" % {
187 "gzip" : config_external_gzip,
188 "file" : pspath
189 }
190 os.system(cmd)
191 os.system("chmod 644 " + psgzpath)
192 os.system("chmod 644 " + logpath)
193
194 # Generate PNG
195 if (not os.path.exists(pngpath)) and show_score:
196 # delete any old stuff
197 cmd = 'rm -f %s/%s*.ppm' % (config_tmp_dir, name)
198 os.system(cmd)
199
200 # Use ghostscript to convert ps to pnm files
201 options = "-dNOPAUSE -q -dBATCH -sPAPERSIZE=letter -sDEVICE=ppmraw -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -r120x120 -sOutputFile=%s%%003d.ppm" % name
202 cmd = 'cd %(workingdir)s ; %(gs)s %(options)s %(infile)s > /dev/null 2>&1' % {
203 "workingdir" : config_tmp_dir,
204 "gs" : config_external_gs,
205 "options" : options,
206 "infile" : pspath
207 }
208 os.system(cmd)
209
210 # Concatenate pnm files into one file
211 cmd = 'cd %(workingdir)s ; %(pnmcat)s %(orientation)s %(name)s*.ppm 2> /dev/null | %(pnmcrop)s 2> /dev/null | %(rasterize)s > %(outfile)s 2> /dev/null' % {
212 "workingdir" : config_tmp_dir,
213 "pnmcat" : config_external_pnmcat,
214 "orientation" : config_score_orientation,
215 "name" : name,
216 "pnmcrop" : config_external_pnmcrop,
217 "rasterize" : config_external_rasterize,
218 "outfile" : pngpath
219 }
220 os.system(cmd)
221 os.system("chmod 644 " + pngpath)
222
223 # Generate MIDI file
224 if not os.path.exists(midipath):
225 data = open(abcpath, "w")
226 data.write('%s' % texstr)
227 data.close()
228
229 options = ""
230 cmd = "cd %(workingdir)s ; %(abc2midi)s %(infile)s %(options)s -o %(outfile)s >> %(logfile)s 2>&1" % {
231 "workingdir" : config_tmp_dir,
232 "abc2midi": config_external_abc2midi,
233 "options": options,
234 "outfile" : midipath,
235 "infile": abcpath,
236 "logfile": logpath
237 }
238 os.system(cmd)
239 os.system("chmod 644 " + midipath)
240 os.system("chmod 644 " + abcpath)
241 os.system("chmod 644 " + logpath)
242
243
244
245 # Clean up junk (unzipped score if using zipped scores)
246 if config_zip_scores:
247 os.system("rm -f " + pspath)
248
249 # Generate page
250 # if show_code or show_score:
251 request.write(formatter.paragraph(1))
252 request.write(formatter.table(1))
253
254 request.write(formatter.table_row(1))
255 request.write(formatter.table_cell(1))
256 request.write(formatter.paragraph(1))
257 request.write(formatter.strong(1))
258 request.write(formatter.emphasis(1))
259 request.write(formatter.text(title))
260 request.write(formatter.emphasis(0))
261 request.write(formatter.strong(0))
262 request.write(formatter.linebreak(preformatted=0))
263 request.write(formatter.url(abcurl, text="ABC source file"))
264 request.write(formatter.linebreak(preformatted=0))
265 request.write(formatter.url(psurl, text="PostScript score"))
266 request.write(formatter.linebreak(preformatted=0))
267 request.write(formatter.url(midiurl, text="MIDI rendition"))
268 request.write(formatter.linebreak(preformatted=0))
269 request.write(formatter.url(logurl, text="Compilation log"))
270 request.write(formatter.paragraph(0))
271 request.write(formatter.table_cell(0))
272 request.write(formatter.table_row(0))
273
274 if 0:#show_midi:
275 request.write(formatter.table_row(1))
276 request.write(formatter.table_cell(1))
277 request.write(formatter.preformatted(1))
278 request.write(formatter.rawHTML("<embed src=%s width=120 height=40 align=center>" % midiurl))
279 request.write(formatter.preformatted(0))
280 request.write(formatter.table_cell(0))
281 request.write(formatter.table_row(0))
282
283 if show_score:
284 request.write(formatter.table_row(1))
285 request.write(formatter.table_cell(1))
286 request.write(formatter.url(pngurl))
287 request.write(formatter.table_cell(0))
288 request.write(formatter.table_row(0))
289
290 if show_code:
291 request.write(formatter.table_row(1))
292 request.write(formatter.table_cell(1))
293 request.write(formatter.preformatted(1))
294 request.write(formatter.rawHTML(colorize(lines)))
295 request.write(formatter.preformatted(0))
296 request.write(formatter.table_cell(0))
297 request.write(formatter.table_row(0))
298
299 request.write(formatter.table(0))
300 request.write(formatter.paragraph(0))
301
302 # Old way with just one link
303 #request.write(formatter.url(psurl, text=title))
Attached Files
To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.You are not allowed to attach a file to this page.