Attachment 'AbcMusic.py'

Download

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

You are not allowed to attach a file to this page.