lilypond-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Numbered musical notation (Jianpu)


From: Silas Brown
Subject: Re: Numbered musical notation (Jianpu)
Date: Sat, 6 Jun 2009 19:59:57 +0000 (UTC)
User-agent: Loom/3.14 (http://gmane.org/)

Continuing the thread from November 2007:
(see http://www.mail-archive.com/address@hidden/msg32740.html )

Here is a Python hack that can add numbered notation (Chinese jianpu) to a line
of music.  The numbered notation is added as ^\markup commands that include
appropriate EPS files.  These EPS files are generated using pslatex (you need
the PostScript fonts for LaTeX, although you could substitute Computer Modern
fonts by replacing pslatex with latex but then the jianpu numbers will not match
Lilypond's other text).  The music parser is extremely basic, so don't try it on
anything too complicated.  Octaves must be absolute, and must be in the range c'
to b'''.  However it is OK not to specify length on every note.  Numbering with
1=C is assumed (although the script can easily be adapted to other numberings).

The script works well for me in Lilypond 2.10.33.  However it does not work so
well in 2.12.2 because the ^\markup commands are re-positioned so much (which is
a good attempt to avoid collisions, but it often results in the jianpu numbers
being printed at different heights just because they are a little close to each
other).  Does anybody know how to do it better in 2.12.2?

def makeEPS(epsFile,texString):
    try: return open(epsFile) # does it exist already?
    except: pass
    texFile=epsFile[:-3]+"tex"
    dviFile=epsFile[:-3]+"dvi"
    psFile=epsFile[:-3]+"ps"
    open(texFile,"w").write(r"""\documentclass{article}
% we must put our title at the bottom left of
% the paper.  (BoundingBox can correct for
% positioning elsewhere, but Lilypond doesn't
% seem to take the left and bottom parts of the
% boundingbox into account when doing its spacing.)
\usepackage[a4paper,lmargin=0mm,rmargin=0mm,tmargin=0mm,bmargin=0mm]{geometry}
\usepackage{color}

% \def\dash{--}  % this is a bit too long
\def\dash{\footnotesize --}

\begin{document}
\pagestyle{empty}
~ \vfill \par \noindent
\textcolor{white}{\rule{0.1pt}{0.8em}} % so -E'd eps is at least that high
"""+texString+r"\end{document}"+"\n")
    r=os.system("pslatex "+texFile+" && dvips -E "+dviFile+' && mv '+psFile+'
'+epsFile)
    assert not r, "Something went wrong with TeX"

import os,string,re

# ensure all notes above c' have lengths, plus rests
# (but try not to add lengths in wrong places - this is very basic)
def addLengths(dat):
    ret=[] ; i=0
    while i<len(dat):
        ret.append(dat[i]) ; i += 1
        if ord('a')<=ord(dat[i-1])<=ord('g') and dat[i]=="'":
            while dat[i]=="'":
                ret.append(dat[i]) ; i += 1
            if dat[i] in string.digits:
                currentLength = ""
                j = i
                while dat[j] in string.digits or dat[j]==".":
                    currentLength += dat[j]
                    j += 1
            else: ret.append(currentLength)
        elif dat[i-1] in "rR" and not dat[i-2].strip() and ((dat[i] in
string.digits and dat[i+1] in ". ") or not dat[i].strip()):
            if dat[i] in string.digits:
                currentLength = ""
                j = i
                while dat[j] in string.digits or dat[j]==".":
                    currentLength += dat[j]
                    j += 1
            else: ret.append(currentLength)
    return ''.join(ret)

def addJianpu(musicWithLengths):
  for duration in [8,4,2,1]:
    if duration in [2,4]: toDot=[0,1]
    else: toDot=[0]
    for dots in toDot:
      for octave in range(4):
        for letter,number in zip("r c d e f g a b".split(),range(8)):
          if number and not octave: continue # don't do octave 0
          if octave and not number: continue # except for rests
          if duration==1 and not number: continue # don't do r1's
          sub = letter+("'"*octave)+str(duration)+("."*dots)
          r = str(number)
          if number:
            if octave==2: r=r"\."+r   # dot above
            elif octave==3: r=r'\"'+r # 2 dots above
            elif octave==0: r=r'\d'+r # dot below
          if duration==8: r=r"\underbar{"+r+"}"
          elif duration==4 and dots: r += " ."
          elif duration==2:
              if number: dash = " \dash{}"
              else: dash = " 0"
              r += dash
              if dots: r += dash
          elif duration==1:
              if number: r += " \dash{} \dash{} \dash{}"
              else: r += " 0 0 0"
          epsFname="j"+str(number)+str(duration)+("d"*dots)+str(octave)+".eps"
          tieEpsFname="jT"+str(duration)+("d"*dots)+str(octave)+".eps"
          makeEPS(epsFname,r)
          makeEPS(tieEpsFname,"\dash{} "+" ".join(r.split()[1:]))
          for charAfter in [" ","\t","}","%","\n"]:
             musicWithLengths = musicWithLengths.replace(sub+charAfter,
                sub+r" ^\markup{ \epsfile #Y #2.5 
#"+'"'+epsFname+'"}'+charAfter)
             musicWithLengths = re.sub(r"(~[^']*''*[1-8]*\.*) ..markup. .epsfile
#Y #2.5 #"+'"'+epsFname+'"}',r"\1 ^\\markup{ \\epsfile #Y #2.5
#"+'"'+tieEpsFname+'"}',musicWithLengths)
  return musicWithLengths

while True:
    r = raw_input("Enter some music: ")
    print addJianpu(addLengths(r))






reply via email to

[Prev in Thread] Current Thread [Next in Thread]