+1.3.19.hwn1
+==========
+
+* Clean up font-metric hierarchy, use Adobe AFM code to parse AFM files.
+Cleanup mf-to-table.py
+
+* Fixed embarassing slur bug.
+
1.3.19.jcn1
==========
. * use hash tabs iso. alist_ for elt property?
. * fix tremolos.
. * internationalize GUILE msgs.
-. * with lily 1.3.17, i'm seeing tuplet markings slice mercilessly through
-whatever stands in their way. for an example, see
-http://www4.smart.net/~jcovey/tmp/smith/closing.ps.gz
-on page 2, end of the second system. is there any way around this?
. * unbroken marks.
. * put property test files in refman.
-. * use gnome-print ParseAFM
. * fix slurdotted!
. * alignment within @itemize
. * interstaff stems
. * script columns
. * Must stop before this music ends:
verse=\lyrics {
-. * input/bugs/clef.sly: clef changes go missing
-. * clean up font metric handling.
. * input/test/grace.sly: wierd big spacing on grace notes
. * TODO^2:
. * make a TODO.texi, like http://www.gnu.org/software/guile/ideas.html
. * staffside spanner (crescendo!) along with staffswitch.
. * * auto melismaBusy for beams.
-. *
-> \context Staff <
+. * \context Staff <
> {\voiceone''4. r8}
> \voicetwo c,4 r4}
> >
-. * sort out breve shapes.
. * \time forces keysig?
.* STUFF
The words are aligned with the main note, not the start of the
grace note. This is usually wrong, but is sometimes right.
. * tie-direction
-. * repeats and partial measures.
. * rhythmic staff & accidentals.
. * use melismaBusy in Lyric context to typeset melismata correctly.
. * ly2dvi/lilypond logfile.
. * msgfmt -o check?
. * collision of lyrics with span_bars. See star-spangled.
. * It is impossible to typeset two textual scripts that are stacked
- on top of eachother and avoids note collisions and at the same
+ on top of each other and avoids note collisions and at the same
time are typeset with different textStyle. I tried to move around
the text_engraver and other engravers between Voice and Thread
but the granularity is not fine enough, the scripts have to
page three, the c-sharp on the second line should be a quarter with
a circle, not a quarter tied to a sixteenth. is this at all
possible with lily?
-. * make dependencies () a virtual function.
. * deprecate hangOnClef.
. * Abstraction for engravers:
. * make "in-between" engraver (Tie)
. * make wide_spanner_engraver (line_group_spanner, staff_symbol)
. * store req -> element, element -> element causes for warnings
-. * compulsory hshift
. * My wish list for lyrics. I dream of a time when I will have enough time to
become familiar enough with the source code to be able to implement some of
these myself, but I don't know when that will be, so I thought I'd "publish"
. * --prefix option?
. * -I option per filetype?
. * kpathsea?
-. * fix vertical alignment and stafflines
. * declaring Performers
. * text-items clash with stems/beams
. * --include, -I option for ly2dvi (pass on to lily)
* { a4 a16 } c <-- duration of c?
* < a4 b8 > c <-- duration of c?
. * \tempo 4. = 90;
-. * make sure all ex's have a mudela-version
. * do rest-collisions for Multi_measure_rests as well.
. * split error/warning in error/warning/non_fatal_error
-. * add a Duration_convert member to Duration_iter to set parameters.
- Junk global duration settings.
. * discourage breaking of slurs
. * fix variable define/lookup parser global<->paper
. * fix title/instrument placements; see input/test/title.ly
. * patch: don't touch timestamp if all patches fail.
. * MetaPost: should not generate setgray for unfill
-
-. * mf-to-table -> add space 'before ; in AFM output. (-> check AFM
-spec. Is this a bug in afm2tfm?)
. * check out GCC signatures?
. * glibc 2.0:
f = fopen ("/dev/null", "r")
. * slurs
. * accents
. * dynamics
-> Would it be hard to add support for proper dynamics in MIDI output? I
-> would really like to have this feature...
-
-Concretely spoken, for dynamics you have to write a performer
-(Dynamics_performer), that will take the input requests. If I
-understand correctly, every MIDI note played must have its dynamic
-strength set separately. That means the the Dynamics_performer must
-set the strength of every Audio_note it finds. This means that one
-has to modify existing Audio items. The best way of doing this is
-with a broadcast/acknowledge process.
-
-So the best way of handling this, is
-
- 1 supporting dynamic settings in Audio_note
-
- 2 Write a Dynamics_performer that will modify
- any notes it finds to set appropriate strengths.
-
-I'd say that the work involved is not hard, but you have to be fluent
-with C++ and need some insight into the working of Notation Contexts
-and friends. I guess I could do it in a day or so, but if you are not
-so fluent with the inner workings of LilyPond, it could take you some
-more time (A few more days?).
-
-Please note, that I am *not* going to code this myself: my days are
-valuable, and I think I have more interesting things to do than fixing
-the MIDI output (I don't even have a soundcard). But I *do* want to help
-you or other people with implementing this, so if you need help, don't
-hesitate to ask.
. * account for rhythmic position in measure
. * etc.
. * write Dynamic_line (to group dynamics horizontally)
-
. * handle EOF graciously in error messages.
. * midi esp.: use I32 iso int where 32 bits are needed (or assumed...)
% --|--- --|---
(where "to" is a tiny bow)
-. * auxilliary file for caching info.
-
. * Text_crescendo
.* IDEAS
PACKAGE_NAME=LilyPond
MAJOR_VERSION=1
MINOR_VERSION=3
-PATCH_LEVEL=19
-MY_PATCH_LEVEL=jcn1
+PATCH_LEVEL=20
+MY_PATCH_LEVEL=
# use the above to send patches: MY_PATCH_LEVEL is always empty for a
# released version.
import re
import time
-(options, files) = getopt.getopt(
- sys.argv[1:], 'a:d:hl:o:p:t:',
- ['afm=', 'outdir=', 'dep=', 'tex=', 'debug', 'help', 'package='])
-
-for opt in options:
- o = opt[0]
- a = opt[1]
- if o == '-p' or o == '--package':
- topdir = a
-
-def gulp_file(f):
- try:
- i = open(f)
- i.seek (0, 2)
- n = i.tell ()
- i.seek (0,0)
- except:
- print 'can\'t open file: ' + f + '\n'
- return ''
- s = i.read (n)
- if len (s) <= 0:
- print 'gulped empty file: ' + f + '\n'
- i.close ()
- return s
-
-version = '0.9'
postfixes = ['log', 'dvi', '2602gf', 'tfm']
-print re
-
def read_log_file (fn):
- str = gulp_file (fn)
+ str = open (fn).read ()
str = re.sub ('\n', '', str)
str = re.sub ('[\t ]+', ' ', str)
return (autolines, deps)
-class Afm_file:
- def print_dimen(self, f):
- f = f * 1000 / self.fontsize
-
- dimstr = '%.2f' % f
-
- # try to mask rounding errors
- if (dimstr == '-0.00'):
- dimstr = '0.00'
- self.write( dimstr +' ');
- def def_symbol (self, code, lily_id, tex_id, xdim, ydim):
- xdim = map (string.atof, xdim)
- ydim = map (string.atof, ydim)
+class Char_metric:
+ def __init__ (self):
+ pass
+
+
+def parse_logfile (fn):
+ (autolines, deps) = read_log_file (fn)
+ charmetrics = []
+ global_info = {}
+ group = ''
+
+ for l in autolines:
+ tags = string.split(l, '@:')
+ if tags[0] == 'group':
+ group = tags[1]
+ elif tags[0] == 'char':
+ m = {
+ 'description': tags[1],
+ 'name': group + '-' + tags[7],
+ 'tex': tags[8],
+ 'code': string.atoi (tags[2]),
+ 'breapth':string.atof (tags[3]),
+ 'width': string.atof (tags[4]),
+ 'depth':string.atof (tags[5]),
+ 'height':string.atof (tags[6])
+ }
+ charmetrics.append (m)
+ elif tags[0] == 'font':
+ global_info['FontName'] = string.join (tags[1:])
+ global_info['FontFamily']=tags[1]
- wid = xdim[0] + xdim[1]
- self.write ('C %s ; ' % code)
- self.write ('WX ')
- self.print_dimen (wid)
-
- self.write (' ; N %s-%s ; B ' % (self.groupname, lily_id))
-
- self.print_dimen(-xdim [0])
- self.print_dimen(-ydim [0])
- self.print_dimen(xdim [1])
- self.print_dimen(ydim [1])
-
- self.write (' ;\n');
- def write (self, str):
- self.file.write (str)
- def __init__ (self, fn):
- self.file = open (fn,'w')
- def start (self,nm):
- self.write ('Start%s\n' % nm)
- def end (self,nm):
- self.write ('End%s\n' % nm)
+ return (global_info, charmetrics, deps)
-
-
-class Log_reader:
- """Read logs, destill info, and put into output files"""
- def output_label(self, line):
-
- if not line:
- return;
-
- tags = string.split(line, '@:')
- label = tags[0]
- name = tags[1]
- afm = self.afmfile
-
- if tags[0] == 'font':
- self.texfile.write("% name\n")
-
- afm.write ('FontName %s\n' % name)
- afm.start ('FontMetrics')
- afm.start ('CharMetrics')
- afm.fontsize = string.atof(tags[2])
- elif label == "group":
- self.texfile.write("% " + name + "\n")
- afm.groupname = name
- elif label == "puorg":
- self.texfile.write("\n")
- elif label == "tnof":
- afm.end ('CharMetrics')
- afm.end('FontMetrics');
- elif label == "char":
- code = tags[2]
- id = tags [7]
- texstr = tags [8]
- xdim = tags[3:5]
- ydim = tags[5:7]
-
- self.texfile.write("\\def\\feta%s{\\char%s}\n" % (texstr, code))
- afm.def_symbol (code, id, texstr, xdim, ydim)
- else:
- raise 'unknown label: ' + label
-
- def writedeps (self, deps):
- if not len (deps):
- sys.stderr.write ('Huh, no main target??')
- return
- filename = deps[0]
- split = os.path.splitext(filename)
- basename=split[0];
-
- targets = map (lambda x,y = basename, z = self.outdir: z + '/' + y + '.' + x, postfixes)
- depstring = reduce(lambda x,y: x + ' ' + y, deps)
- dependencies = map (lambda x, y=depstring: x + ': ' + y, targets)
- for x in dependencies:
- self.depfile.write (x + '\n')
-
- def do_file(self,filenm):
- self.texfile.write ('\n% input from ' + filenm + '\n')
- (autolines, deps) = read_log_file (filenm)
- for a in autolines:
- self.output_label(a)
-
- self.writedeps (deps)
+def write_afm_char_metric(file, charmetric):
- def __init__(self, texfile_nm, depfile_nm, afmfile_nm):
- self.texfile = open(texfile_nm, 'w')
- self.depfile = open (depfile_nm, 'wb')
- self.afmfile = Afm_file (afmfile_nm)
- headerstr = '%% Creator: %s\n%% Automatically generated on\n%% Do not edit' % \
- (program_id() )
-
- self.texfile.write(headerstr)
- self.depfile.write ('# automatically generated by %s\n' % program_id ())
-
- def close(self):
- self.texfile.close()
- self.depfile.close ()
-
- def __del__(self):
- self.close()
-
-def today_str():
- return time.asctime(time.localtime(time.time()))
+ f = 1000;
+ tup = (charmetric['code'],
+ charmetric['width'] + charmetric['breapth'],
+ charmetric['name'],
+ -charmetric['breapth'] *f,
+ -charmetric['depth']*f,
+ charmetric['width']*f,
+ charmetric['height']*f)
-def program_id():
- return 'mf-to-table.py version ' + version;
+
+ file.write ('C %d ; WX %d ; N %s ; B %d %d %d %d ;\n'% tup)
+
+def write_afm_metric (file, global_info, charmetrics):
+ file.write (r"""
+StartFontMetrics 2.0
+Comment Automatically generated by mf-to-table.py
+""")
+ for (k,v) in global_info.items():
+ file.write ("%s %s\n" % (k,v))
+ file.write ('StartCharMetrics %d\n' % len(charmetrics ))
+ for m in charmetrics:
+ write_afm_char_metric (file,m)
+ file.write ('EndCharMetrics\n')
+ file.write ('EndFontMetrics %d\n')
+
+
+def write_tex_defs (file, global_info, charmetrics):
+ nm = global_info['FontFamily']
+ for m in charmetrics:
+ file.write (r'''\def\%s%s{\char%d}%s''' % (nm, m['tex'], m['code'],'\n'))
+
+
+def write_deps (file, deps, targets):
+ for t in targets:
+ file.write ('%s '% t)
+ file.write (": ")
+ for d in deps:
+ file.write ('%s ' % d)
+ file.write ('\n')
-def identify():
- sys.stdout.write(program_id() + '\n')
-
def help():
sys.stdout.write(r"""Usage: mf-to-table [options] LOGFILEs
Generate feta metrics table from preparated feta log\n
sys.exit (0)
-def main():
- identify()
- texfile_nm = '';
- depfile_nm = ''
- afmfile_nm = ''
- outdir_prefix = '.'
- for opt in options:
+(options, files) = getopt.getopt(
+ sys.argv[1:], 'a:d:hl:o:p:t:',
+ ['afm=', 'outdir=', 'dep=', 'tex=', 'debug', 'help', 'package='])
+
+
+texfile_nm = '';
+depfile_nm = ''
+afmfile_nm = ''
+outdir_prefix = '.'
+
+for opt in options:
o = opt[0]
a = opt[1]
if o == '--dep' or o == '-d':
- depfile_nm = a
+ depfile_nm = a
elif o == '--outdir' or o == '-o':
- outdir_prefix = a
+ outdir_prefix = a
elif o == '--tex' or o == '-t':
- texfile_nm = a
+ texfile_nm = a
elif o== '--help' or o == '-h':
- help()
+ help()
elif o=='--afm' or o == '-a':
- afmfile_nm = a
+ afmfile_nm = a
elif o == '--debug':
- debug_b = 1
+ debug_b = 1
elif o == '-p' or o == '--package':
- topdir = a
+ topdir = a
else:
- print o
- raise getopt.error
+ print o
+ raise getopt.error
- log_reader = Log_reader( texfile_nm, depfile_nm, afmfile_nm)
- log_reader.outdir = outdir_prefix
- for filenm in files:
- log_reader.do_file(filenm)
- log_reader.close()
+for filenm in files:
+ (g,m, deps) = parse_logfile (filenm)
+ afm = open (afmfile_nm, 'w')
+ write_afm_metric (afm, g,m)
+ write_tex_defs (open (texfile_nm, 'w'), g, m)
+ write_deps (open (depfile_nm, 'w'), deps, [texfile_nm, afmfile_nm])
-main()
--- /dev/null
+#!@PYTHON@
+
+# musedata = musedata.stanford.edu
+# musedata = COBOL for musicians.
+# todo: rewrite this.
+
+import re
+import sys
+import string
+
+f = open (sys.argv[1])
+lines =f.readlines()
+
+def chomp (x):
+ return re.sub ('[\r\n \t]+$','', x)
+
+lines = map (chomp, lines)
+
+default_header_dict = {
+ 'tagline' :'automatically converted from Musedata',
+ 'copyright' : 'all rights reserved -- free for noncommercial use'
+ }
+
+# Jezus, wat een ranzig formaat. (2am)
+def parse_header (lines):
+ d = default_header_dict
+ enter = string.split (lines[3], ' ')
+ d['enteredby'] = string.join (enter[1:])
+ d['enteredon'] = enter[0]
+ d['opus'] = lines[4]
+ d['source'] = lines[5]
+ d['title'] = lines[6]
+ d['subtitle'] = lines[7]
+ d['instrument']= lines[8]
+ d['musedatamisc'] =lines[9]
+ d['musedatagroups'] =lines[10]
+ d['musedatagroupnumber']=lines[11]
+
+ return d
+
+clef_dict = {
+04: 'treble',
+13 : 'alto',
+22: 'bass',
+
+}
+
+def get_clef(s):
+ return '\\clef "%s";\n' % clef_dict [string.atoi (s)]
+
+def get_mudela_notename (p, ac):
+ if p > 5:
+ p = p - 7
+ s = chr (p + ord ('c'))
+ infix = 'i'
+ if ac < 0:
+ infix = 'e'
+ ac = -ac
+
+ while ac:
+ s = s + infix + 's'
+ ac = ac - 1
+ return s
+
+def get_key (s):
+ i = string.atoi (s)
+ return ''
+
+def get_timesig (s):
+ return '\\time %s;\n' % s
+
+
+divisions = 4
+def get_divisions_per_quarter (s):
+ divisions = string.atoi (s)
+ return ''
+
+def get_directive (s):
+ return '%% %s\n' % s
+
+def get_transposing (s):
+ return ''
+
+def get_num_instruments (s):
+ return ''
+
+attr_dict = {
+ 'C' : get_clef,
+ 'K' : get_key ,
+ 'T' : get_timesig,
+ 'Q' : get_divisions_per_quarter,
+ 'D' : get_directive,
+ 'X' : get_transposing,
+ 'I': get_num_instruments,
+ }
+
+def parse_musical_attributes (l):
+ s = ''
+ l = l[1:]
+ atts = re.split('[ \t]+', l)
+ for a in atts:
+ if not a:
+ continue
+ m = re.search ('(.):(.*)', a)
+ if m == None:
+ print 'Huh, unknown attr `%s\'' % a
+ continue
+
+ s = s + attr_dict[m.group(1)](m.group (2))
+ return s
+
+
+def get_mudela_pitch (n, a, o):
+ c = '\''
+ if o < 1:
+ c = ','
+ o = 1 - o
+
+ return get_mudela_notename (n,a) + '%s' % c * o
+
+def dump_header (h, out):
+ out.write ('\\header {\n')
+ for tup in h.items ():
+ out.write ('\t%s = \"%s\";\n' % tup)
+ out.write ('}\n')
+
+header_dict = parse_header (lines[0:12])
+dump_header (header_dict, sys.stdout)
+
+
+lines = lines [12:]
+
+
+def parse_line_comment (l):
+ return re.sub ('@' , '%' , l)
+
+def parse_note_line (l):
+ pitch = ((ord (l[0]) -ord('A')) + 5) % 7
+ acc = 0
+ l= l[1:]
+ while l[0] == 'f':
+ l= l[1:]
+ acc = acc - 1
+ while l[0] == '#':
+ l= l[1:]
+ acc = acc + 1
+ while l[0] in ' \t':
+ l= l[1:]
+
+ oct = 0
+ if l[0] in '0123456789':
+ oct = string.atoi (l[0]) - 4
+ l= l[1:]
+
+ while l[0] in ' \t':
+ l= l[1:]
+
+
+ print get_mudela_pitch (pitch,acc,oct), parse_duration(l[:2])
+ l = l[2:]
+
+
+
+
+def parse_duration (l):
+ s = ''
+ while l[0] in '0123456789':
+ s = s + l[0]
+ l= l[1:]
+ print l
+ num = string.atoi (s)
+ den = 4 * divisions
+
+ current_dots = 0
+ try_dots = [3, 2, 1]
+ for d in try_dots:
+ f = 1 << d
+ multiplier = (2*f-1)
+ if num % multiplier == 0 and den % f == 0:
+ num = num / multiplier
+ den = den / f
+ current_dots = current_dots + d
+
+ if num <> 1:
+ sys.stderr.write ('huh. Durations left')
+ return '%s%s' % (den, '.' * current_dots)
+
+comment_switch = 0
+for l in lines:
+ if l[0] == '&':
+ comment_switch = not comment_switch
+ if comment_switch:
+ l= l[1:]
+ print '%{'
+ else:
+ print '%}'
+
+ if comment_switch:
+ print l
+ continue
+
+ if 0:
+ pass
+ elif l[0] == '$':
+ print parse_musical_attributes (l)
+ elif l[0] == '@':
+ parse_line_comment (l)
+
+ elif l[0] in 'ABCDEFG':
+ parse_note_line (l)
*/
-/* Bounding box definition. Used for the Font BBox as well as the
- * Character BBox.
+/* Bounding box definition. Used for the Font AFM_BBox as well as the
+ * Character AFM_BBox.
*/
typedef struct
{
int lly; /* lower left y-position */
int urx; /* upper right x-position */
int ury; /* upper right y-position */
-} BBox;
+} AFM_BBox;
/* Global Font information.
char *weight; /* key: Weight */
float italicAngle; /* key: ItalicAngle */
BOOL isFixedPitch; /* key: IsFixedPitch */
- BBox fontBBox; /* key: FontBBox */
+ AFM_BBox fontBBox; /* key: FontBBox */
int underlinePosition; /* key: UnderlinePosition */
int underlineThickness; /* key: UnderlineThickness */
char *version; /* key: Version */
{
char *succ, *lig;
struct _t_ligature *next;
-} Ligature;
+} AFM_Ligature;
/* Character Metric Information. This structure is used only if ALL
wx, /* key: WX */
wy; /* together wx and wy are associated with key: W */
char *name; /* key: N */
- BBox charBBox; /* key: B */
- Ligature *ligs; /* key: L (linked list; not a fixed number of Ls */
+ AFM_BBox charBBox; /* key: B */
+ AFM_Ligature *ligs; /* key: L (linked list; not a fixed number of Ls */
} AFM_CharMetricInfo;
* The possible return codes from parseFile are defined above.
*/
-int parseFile (FILE *fp, AFM_Font_info **fi, FLAGS flags);
-void parseFileFree (AFM_Font_info *fi);
+int AFM_parseFile (FILE *fp, AFM_Font_info **fi, FLAGS flags);
+void AFM_free (AFM_Font_info *fi);
temp->charBBox.ury = atoi(token(fp));
break;
case LIGATURE: {
- Ligature **tail = &(temp->ligs);
- Ligature *node = *tail;
+ AFM_Ligature **tail = &(temp->ligs);
+ AFM_Ligature *node = *tail;
if (*tail != NULL)
{
tail = &(node->next);
}
- *tail = (Ligature *) calloc(1, sizeof(Ligature));
+ *tail = (AFM_Ligature *) calloc(1, sizeof(AFM_Ligature));
keyword = token(fp);
(*tail)->succ = (char *) malloc(strlen(keyword) + 1);
strcpy((*tail)->succ, keyword);
* pointer upon return of this function is undefined.
*/
-extern int parseFile (FILE *fp, AFM_Font_info **fi, int flags)
+extern int AFM_parseFile (FILE *fp, AFM_Font_info **fi, int flags)
{
int code = AFM_ok; /* return code from each of the parsing routines */
void
-parseFileFree (AFM_Font_info *fi)
+AFM_free (AFM_Font_info *fi)
{
if (fi->gfi) {
free (fi->gfi->afmVersion);
for (i = 0; i < fi->numOfChars; i++) {
free (fi->cmi[i].name);
while (fi->cmi[i].ligs) {
- Ligature *tmp;
+ AFM_Ligature *tmp;
tmp = fi->cmi[i].ligs;
free (tmp->succ);
free (tmp->lig);
-/*
- afm-reader.cc -- implement Adobe_font_metric_file
-
- source file of the GNU LilyPond music typesetter
-
- (c) 1998--2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
-
- */
-
-#include "direction.hh"
-#include "afm.hh"
-#include "data-file.hh"
-#include "string-convert.hh"
-#include <ctype.h>
-
-
-Box
-parse_box (Array<String> a)
-{
- Box b;
- int i=0;
- b[X_AXIS][SMALLER] = a[i++].value_f ();
- b[Y_AXIS][SMALLER] = a[i++].value_f ();
- b[X_AXIS][BIGGER] = a[i++].value_f ();
- b[Y_AXIS][BIGGER] = a[i++].value_f ();
- return b;
-}
-
-String
-strip_leading_white (String c)
-{
- int i=0;
- while (isspace(c[i]))
- i++;
- c = c.cut_str (i, INT_MAX);
- return c;
-}
-
-Adobe_font_char_metric
-read_char_metric (String s, int size)
-{
- Adobe_font_char_metric char_metric;
- char_metric.size_ = size;
- Array<String> a= String_convert::split_arr (s, ';');
- for (int i=0; i < a.size (); i++)
- {
- String c = strip_leading_white (a[i]);
-
- Array<String> b = String_convert::split_arr (c, ' ');
- if (!b.size ())
- continue;
- if (b[0] == "C")
- char_metric.C_ = b[1].value_i ();
- else if (b[0] == "WX")
- char_metric.WX_ = b[1].value_f ();
- else if (b[0] == "N")
- char_metric.N_ = strip_leading_white (b[1]);
- else if (b[0] == "B")
- char_metric.B_ = parse_box (b.slice (1, b.size()));
- }
- return char_metric;
-}
-
-void
-Adobe_font_metric::read_char_metrics (Data_file &input, int size)
-{
- while (!input.eof_b ())
- {
- input.gobble_leading_white ();
- String s= input.get_line ();
- if (s == "EndCharMetrics")
- return ;
- Adobe_font_char_metric afm_char =read_char_metric (s, size);
- char_metrics_.push (afm_char);
- int i = char_metrics_.size ()-1;
-
- // TFM files uses neg. charcodes to store Space
- if (afm_char.C_ >= 0)
- ascii_to_metric_idx_ [afm_char.C_] = i;
- name_to_metric_dict_ [afm_char.N_] = i;
- }
-}
-
-#define READSTRING(k) if (key == #k) { \
- afm->k ## _ = input.get_line (); continue; }
-#define READBOX(b) if (key == #b) { \
- afm->b ## _ = read_box (input); continue; }
-#define READREAL(r) if (key == #r) { \
- afm->r ## _ = read_real (input); continue; }
-
-Real
-read_real(Data_file &d)
-{
- String s = d.get_word ();
- d.gobble_white ();
- return s.value_f ();
-}
-
-
-Box
-read_box ( Data_file &d)
-{
- Box b;
- b[X_AXIS][SMALLER] = read_real (d);
- b[Y_AXIS][SMALLER] = read_real (d);
- b[X_AXIS][BIGGER] = read_real (d);
- b[Y_AXIS][BIGGER] = read_real (d);
- return b;
-}
-
-Adobe_font_metric *
-read_afm_file (String fn)
-{
- Data_file input (fn);
-
- assert (!input.eof_b ());
-
- int i = fn.index_i(".afm");
- for (; i>0 && isdigit(fn[--i]); )
- {}
- int font_size = String_convert::dec2_i(fn.cut_str(i+1,INT_MAX));
-
- Adobe_font_metric *afm = new Adobe_font_metric;
- for (i=0; i < 256; i++)
- {
- afm->ascii_to_metric_idx_.push (-1);
- }
-
- while (!input.eof_b ())
- {
- input.gobble_leading_white ();
- String w = input.get_word ();
- if (w == "StartFontMetrics")
- break;
- input.get_line ();
- }
-
- while (!input.eof_b ())
- {
- input.gobble_leading_white ();
- String key = input.get_word ();
- if (key == "Comment")
- continue;
-
- READSTRING(FontName);
- READSTRING(FullName);
- READSTRING(FamilyName);
- READSTRING(Weight);
- READSTRING(Version);
- READSTRING(Notice);
- READSTRING(EncodingScheme);
- READREAL(ItalicAngle);
- READREAL(UnderlineThickness);
- READREAL(UnderlinePosition);
- READBOX(FontBBox);
- if (key == "StartCharMetrics")
- {
- input.get_line ();
- afm->read_char_metrics (input, font_size);
- }
- if (key == "EndFontMetrics")
- break;
-
- }
-
- /*
- read to EOF
- */
- input.gulp ();
-
- return afm;
-}
-
/*
- afm.cc -- implement Adobe_font_metric
+ afm2.cc -- implement Adobe_font_metric
- source file of the GNU LilyPond music typesetter
+ source file of the Flower Library
- (c) 1998--2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+ (c) 2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
*/
-
#include "afm.hh"
-#include "box.hh"
-#include "direction.hh"
-#include "debug.hh"
-
-Box &
-Adobe_font_char_metric::bbox ()
-{
- return B_;
-}
-
-String &
-Adobe_font_char_metric::name ()
-{
- return N_;
-}
-
-int &
-Adobe_font_char_metric::code ()
-{
- return C_;
-}
-
-Real &
-Adobe_font_char_metric::width ()
-{
- return WX_;
-}
-
-Adobe_font_char_metric::Adobe_font_char_metric ()
-{
- B_ = Box( Interval(0,0), Interval (0,0));
- WX_ = 0.0;
- C_ = 0;
- C_ = -1;
-}
+#include "warn.hh"
-Adobe_font_metric::Adobe_font_metric ()
+Adobe_font_metric::Adobe_font_metric (AFM_Font_info * fi)
{
- ItalicAngle_ = 0.0;
- IsFixedPitch_ = false;
- UnderlinePosition_ =0.;
- UnderlineThickness_=0.;
-}
-
+ font_inf_ = fi;
-Box
-Adobe_font_char_metric::dimensions () const
-{
- Box b= B_;
+ for (int i= 256; i--;)
+ ascii_to_metric_idx_.push (-1);
- b[X_AXIS] *= size_ / 1000.0;
- b[Y_AXIS] *= size_ / 1000.0;
-
- return b;
-}
-
-
-
-#define APPEND_CHAR_METRIC_ELT(k) outstr += to_str (#k) + " " + to_str (k ## _) + "; "
+ for (int i=0; i < fi->numOfChars; i++)
+ {
+ AFM_CharMetricInfo * c = fi->cmi + i;
-String
-box_str (Box b)
-{
- return to_str (b[X_AXIS][SMALLER]) + " " +
- to_str(b[Y_AXIS][SMALLER]) + " " +
- to_str (b[X_AXIS][BIGGER]) + " "+
- to_str (b[Y_AXIS][BIGGER]);
+ ascii_to_metric_idx_[c->code] = i;
+ name_to_metric_dict_[c->name] = i;
+ }
}
-
-#define APPEND_BOX(k) outstr += to_str (#k) + " " + box_str (k ## _) + ";"
-
-String
-Adobe_font_char_metric::str () const
-{
- String outstr ;
-
- APPEND_CHAR_METRIC_ELT (C);
- APPEND_CHAR_METRIC_ELT(N);
- APPEND_CHAR_METRIC_ELT(WX);
- APPEND_BOX(B);
- return outstr + "\n";
-}
-
-#define WRITESTRING(k) outstr += String (#k) + " " + to_str (k ## _) + "\n"
-String
-Adobe_font_metric::str () const
+AFM_CharMetricInfo const *
+Adobe_font_metric::find_ascii_metric (int a , bool warn) const
{
- String outstr;
- WRITESTRING(FontName);
- WRITESTRING(FullName);
- WRITESTRING(FamilyName);
- WRITESTRING(Weight);
- WRITESTRING(Version);
- WRITESTRING(Notice);
- WRITESTRING(EncodingScheme);
- WRITESTRING(ItalicAngle);
- WRITESTRING(UnderlineThickness);
- WRITESTRING(UnderlinePosition);
- outstr += "FontBBox " + box_str (FontBBox_) + "\n";
+ if (ascii_to_metric_idx_[a] >=0)
+ {
+ int code = ascii_to_metric_idx_[a];
+ if (code>=0)
+ {
+ return font_inf_->cmi + code;
+ }
+ }
+ else if (warn )
+ {
+ warning (_f ("Can't find character number: %d", a));
+ }
- for (int i=0; i < char_metrics_.size (); i++)
- outstr += char_metrics_[i].str ();
-
- return outstr;
+ return 0;
}
-Adobe_font_char_metric dummy_static_char_metric;
-
-Adobe_font_char_metric const &
-Adobe_font_metric::find_char (String nm, bool warn) const
+AFM_CharMetricInfo const *
+Adobe_font_metric::find_char_metric (String nm, bool warn) const
{
if (!name_to_metric_dict_.elem_b (nm))
{
{
warning (_f ("Can't find character called: `%s'", nm.ch_C()));
}
- return dummy_static_char_metric;
+ return 0;
}
-
- return char_metrics_[name_to_metric_dict_ [nm]];
+ else
+ return font_inf_->cmi + name_to_metric_dict_ [nm];
}
-Character_metric const *
+Box
Adobe_font_metric::get_char (int code, bool warn) const
{
- return &find_ascii (code,warn);
+ AFM_CharMetricInfo const
+ * c = find_ascii_metric (code,warn);
+ if (c)
+ return afm_bbox_to_box (c->charBBox);
+ else
+ return Box (Interval (0,0),Interval(0,0));
}
-Adobe_font_char_metric const &
-Adobe_font_metric::find_ascii (int a , bool warn) const
+Adobe_font_metric*
+read_afm_file (String nm)
{
- int code = ascii_to_metric_idx_[a];
- if (code>=0)
- {
- return char_metrics_[code];
- }
- else if (warn )
+ FILE *f = fopen (nm.ch_C() , "r");
+
+ AFM_Font_info * fi;
+ int ok = AFM_parseFile (f, &fi, ~1);
+
+ if (ok)
{
- warning (_f ("Can't find character number: %d", a));
+ error (_("Error parsing AFM file"));
+ exit (2);
}
- return dummy_static_char_metric;
+ fclose (f);
+
+ return new Adobe_font_metric (fi);
+}
+
+
+Box
+afm_bbox_to_box (AFM_BBox bb)
+{
+ return Box (Interval (bb.llx, bb.urx)* (1/1000.0),
+ Interval (bb.lly, bb.ury)* (1/1000.0));
+
+}
+
+
+Adobe_font_metric::~Adobe_font_metric ()
+{
+ AFM_free (font_inf_);
}
}
else
{
- Character_metric const *c = get_char ((unsigned char)text[i],false);
+ Box b = get_char ((unsigned char)text[i],false);
// Ugh, use the width of 'x' for unknown characters
- if (c->dimensions()[X_AXIS].length () == 0)
- c = get_char ((unsigned char)'x',false);
+ if (b[X_AXIS].length () == 0)
+ b = get_char ((unsigned char)'x',false);
- w += c->dimensions()[X_AXIS].length ();
- ydims.unite (c->dimensions()[Y_AXIS]);
+ w += b[X_AXIS].length ();
+ ydims.unite (b[Y_AXIS]);
}
}
if (ydims.empty_b ())
return Box(b[X_AXIS]* realmag, b[Y_AXIS]*realmag);
}
-
-Box
-Character_metric::dimensions () const
-{
- return Box(Interval(0,0), Interval(0,0));
-}
-
Font_metric::~Font_metric ()
{
unsmobify_self ();
{
}
-Character_metric::~Character_metric()
-{
-}
-Character_metric const *
+
+Box
Font_metric::get_char (int, bool)const
{
- return 0;
+ return Box (Interval(0,0),Interval (0,0));
}
Scaled_font_metric::Scaled_font_metric (Font_metric* m, int s)
+
/*
afm.hh -- declare Adobe_font_metric
#include "array.hh"
#include "dictionary.hh"
#include "font-metric.hh"
-
-struct Adobe_font_char_metric : Character_metric {
- int C_;
- Real WX_;
- String N_;
- Box B_;
- int size_;
- Box &bbox();
- String &name();
- Real &width();
- int &code ();
-
- String str () const;
- Adobe_font_char_metric ();
- Box dimensions () const;
-};
+#include "parse-afm.hh"
struct Adobe_font_metric : Font_metric {
- String FontName_;
- String FullName_;
- String FamilyName_;
- String Weight_;
- Real ItalicAngle_;
- bool IsFixedPitch_;
- Box FontBBox_;
- Real UnderlinePosition_;
- Real UnderlineThickness_;
- String Version_;
- String Notice_;
- String EncodingScheme_;
- Array<Adobe_font_char_metric> char_metrics_;
+ AFM_Font_info * font_inf_;
+
Array<int> ascii_to_metric_idx_;
Dictionary<int> name_to_metric_dict_;
-
- Adobe_font_char_metric const &find_char (String name, bool warn=true) const;
- Adobe_font_char_metric const &find_ascii (int ascii,bool warn) const;
- String str () const;
- Adobe_font_metric ();
- void read_char_metrics (Data_file &input, int size);
-
- Character_metric const *get_char (int, bool) const;
-};
-Adobe_font_metric *read_afm_file (String fn);
+ Box get_char (int, bool) const;
+ AFM_CharMetricInfo const *find_char_metric (String name, bool warn=true) const;
+ AFM_CharMetricInfo const *find_ascii_metric (int, bool warn=true) const;
+ String str () const;
+ Adobe_font_metric (AFM_Font_info*);
+ ~Adobe_font_metric ();
+};
+Adobe_font_metric * read_afm_file (String fn);
+Box afm_bbox_to_box (AFM_BBox bb);
+
#endif /* AFM_HH */
+++ /dev/null
-/*
- afm.hh -- declare Adobe_font_metric
-
- source file of the GNU LilyPond music typesetter
-
- (c) 1998--2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
-
- */
-
-#ifndef AFM_HH
-#define AFM_HH
-
-#include "string.hh"
-#include "box.hh"
-#include "array.hh"
-#include "dictionary.hh"
-#include "font-metric.hh"
-
-struct Adobe_font_char_metric : Character_metric {
- char_metric_info_;
- Adobe_font_char_metric (AFM_CharMetricInfo afm_inf);
- virtual Box dimensions () const;
-};
-
-struct Adobe_font_metric : Font_metric {
- AFM_Font_info * font_inf_;
- Array<int> ascii_to_metric_idx_;
- Dictionary<int> name_to_metric_dict_;
-
- Character_metric const *get_char (int, bool) const;
- Adobe_font_char_metric const &find_char (String name, bool warn=true) const;
- Adobe_font_char_metric const &find_ascii (int ascii,bool warn) const;
- String str () const;
- Adobe_font_metric (AFM_Font_info*);
-
-};
-
-Adobe_font_metric *read_afm_file (String fn);
-
-
-
-#endif /* AFM_HH */
-
#include "lily-guile.hh"
#include "smobs.hh"
-struct Character_metric
-{
- virtual Box dimensions () const;
- virtual ~Character_metric ();
-};
-
-
struct Font_metric
{
Font_metric ();
SCM name_;
virtual SCM description () const;
- virtual Character_metric const *get_char (int ascii, bool warn) const;
+ virtual Box get_char (int ascii, bool warn) const;
virtual ~Font_metric ();
virtual Box text_dimension (String) const;
Real kern;
};
-struct Tex_font_char_metric : Character_metric
+struct Tex_font_char_metric
{
bool exists_b_;
Char_code code_;
Tex_font_metric ();
void clear (int n);
- Character_metric const *get_char (int, bool) const;
- Tex_font_char_metric const &find_ascii (int ascii, bool warn=true) const;
+ Box get_char (int, bool) const;
+ Tex_font_char_metric const *find_ascii (int ascii, bool warn=true) const;
String str () const;
}
-
-
Molecule
Lookup::afm_find (String s, bool warn) const
{
error (_ ("Aborting"));
}
}
- Adobe_font_char_metric cm = afm_l_->find_char (s, warn);
+ AFM_CharMetricInfo const *cm = afm_l_->find_char_metric (s, warn);
Molecule m;
- if (cm.code () < 0)
+ if (!cm)
{
- /*
- don't want people relying on this kind of dimension.
- */
m.set_empty (false);
return m;
}
Atom at (gh_list (ly_symbol2scm ("char"),
- gh_int2scm (cm.code ()),
+ gh_int2scm (cm->code),
SCM_UNDEFINED));
at.fontify (afm_l_);
- m.dim_ = cm.dimensions();
+ m.dim_ = afm_bbox_to_box (cm->charBBox);
m.add_atom (&at);
return m;
}
Walk through repeat music, and generate events for appropriate times.
UGH. Should use Music_iteration for this.
+
+ Should also queue some event to get timing information reset during
+ 2nd and following voltas.
*/
void
Repeat_engraver::queue_events ()
{
Bezier c (get_curve ());
+ Offset size (c.extent (X_AXIS).length (),
+ c.extent (Y_AXIS).length ());
- Real height_f = c.extent (X_AXIS).length ();
- Real width_f = c.extent (Y_AXIS).length ();
-
dy_f = dy_f_drul_[RIGHT] - dy_f_drul_[LEFT];
if (!fix_broken_b)
dy_f -= interstaff_f;
- Real height_ratio_f = abs (height_f / width_f);
+ Real height_ratio_f = abs (size[Y_AXIS] / size[X_AXIS]);
if (height_ratio_f > height_damp_f)
{
Direction d = (Direction)(- my_dir * (sign (dy_f)));
if (!d)
d = LEFT;
/* take third step */
- Real damp_f = (height_ratio_f - height_damp_f) * width_f / 3;
+ Real damp_f = (height_ratio_f - height_damp_f) * size[X_AXIS] / 3;
/*
if y positions at about the same height, correct both ends
*/
static Tex_font_char_metric dummy_static_char_metric;
-Tex_font_char_metric const &
+Tex_font_char_metric const *
Tex_font_metric::find_ascii (int ascii, bool warn) const
{
if (ascii < ascii_to_metric_idx_.size() && ascii_to_metric_idx_[ascii] >= 0)
- return char_metrics_[ascii_to_metric_idx_ [ascii]];
+ return & char_metrics_[ascii_to_metric_idx_ [ascii]];
else if (warn)
{
warning (_f ("Can't find ascii character: `%d'", ascii));
}
- return dummy_static_char_metric;
+ return &dummy_static_char_metric;
}
-Character_metric const*
+Box
Tex_font_metric::get_char (int a, bool w) const
{
- return &find_ascii (a, w);
+ return find_ascii (a, w)->dimensions ();
}
Begin3
Title: LilyPond
-Version: 1.3.19
-Entered-date: 14JAN00
+Version: 1.3.20
+Entered-date: 17JAN00
Description:
Keywords: music notation typesetting midi fonts engraving
Author: hanwen@cs.uu.nl (Han-Wen Nienhuys)
janneke@gnu.org (Jan Nieuwenhuizen)
Maintained-by: hanwen@stack.nl (Han-Wen Nienhuys)
Primary-site: sunsite.unc.edu /pub/Linux/apps/sound/convert
- 1000k lilypond-1.3.19.tar.gz
+ 1000k lilypond-1.3.20.tar.gz
Original-site: ftp.cs.uu.nl /pub/GNU/LilyPond/development/
- 1000k lilypond-1.3.19.tar.gz
+ 1000k lilypond-1.3.20.tar.gz
Copying-policy: GPL
End
Name: lilypond
-Version: 1.3.19
+Version: 1.3.20
Release: 1
Copyright: GPL
Group: Applications/Publishing
-Source0: ftp.cs.uu.nl:/pub/GNU/LilyPond/development/lilypond-1.3.19.tar.gz
+Source0: ftp.cs.uu.nl:/pub/GNU/LilyPond/development/lilypond-1.3.20.tar.gz
Summary: A program for printing sheet music.
URL: http://www.cs.uu.nl/~hanwen/lilypond
# get Packager from (undocumented?) ~/.rpmmacros!
+++ /dev/null
-#!@PYTHON@
-
-# musedata = musedata.stanford.edu
-# musedata = COBOL for musicians.
-
-import re
-import sys
-import string
-
-f = open (sys.argv[1])
-lines =f.readlines()
-
-def chomp (x):
- return re.sub ('[\r\n \t]+$','', x)
-
-lines = map (chomp, lines)
-
-default_header_dict = {
- 'tagline' :'automatically converted from Musedata',
- 'copyright' : 'all rights reserved -- free for noncommercial use'
- }
-
-# Jezus, wat een ranzig formaat. (2am)
-def parse_header (lines):
- d = default_header_dict
- enter = string.split (lines[3], ' ')
- d['enteredby'] = string.join (enter[1:])
- d['enteredon'] = enter[0]
- d['opus'] = lines[4]
- d['source'] = lines[5]
- d['title'] = lines[6]
- d['subtitle'] = lines[7]
- d['instrument']= lines[8]
- d['musedatamisc'] =lines[9]
- d['musedatagroups'] =lines[10]
- d['musedatagroupnumber']=lines[11]
-
- return d
-
-clef_dict = {
-04: 'treble',
-13 : 'alto',
-22: 'bass',
-
-}
-
-def get_clef(s):
- return '\\clef "%s";\n' % clef_dict [string.atoi (s)]
-
-def get_mudela_notename (p, ac):
- if p > 5:
- p = p - 7
- s = chr (p + ord ('c'))
- infix = 'i'
- if ac < 0:
- infix = 'e'
- ac = -ac
-
- while ac:
- s = s + infix + 's'
- ac = ac - 1
- return s
-
-def get_key (s):
- i = string.atoi (s)
- return ''
-
-def get_timesig (s):
- return '\\time %s;\n' % s
-
-
-divisions = 4
-def get_divisions_per_quarter (s):
- divisions = string.atoi (s)
- return ''
-
-def get_directive (s):
- return '%% %s\n' % s
-
-def get_transposing (s):
- return ''
-
-def get_num_instruments (s):
- return ''
-
-attr_dict = {
- 'C' : get_clef,
- 'K' : get_key ,
- 'T' : get_timesig,
- 'Q' : get_divisions_per_quarter,
- 'D' : get_directive,
- 'X' : get_transposing,
- 'I': get_num_instruments,
- }
-
-def parse_musical_attributes (l):
- s = ''
- l = l[1:]
- atts = re.split('[ \t]+', l)
- for a in atts:
- if not a:
- continue
- m = re.search ('(.):(.*)', a)
- if m == None:
- print 'Huh, unknown attr `%s\'' % a
- continue
-
- s = s + attr_dict[m.group(1)](m.group (2))
- return s
-
-
-def get_mudela_pitch (n, a, o):
- c = '\''
- if o < 1:
- c = ','
- o = 1 - o
-
- return get_mudela_notename (n,a) + '%s' % c * o
-
-def dump_header (h, out):
- out.write ('\\header {\n')
- for tup in h.items ():
- out.write ('\t%s = \"%s\";\n' % tup)
- out.write ('}\n')
-
-header_dict = parse_header (lines[0:12])
-dump_header (header_dict, sys.stdout)
-
-
-lines = lines [12:]
-
-
-def parse_line_comment (l):
- return re.sub ('@' , '%' , l)
-
-def parse_note_line (l):
- pitch = ((ord (l[0]) -ord('A')) + 5) % 7
- acc = 0
- l= l[1:]
- while l[0] == 'f':
- l= l[1:]
- acc = acc - 1
- while l[0] == '#':
- l= l[1:]
- acc = acc + 1
- while l[0] in ' \t':
- l= l[1:]
-
- oct = 0
- if l[0] in '0123456789':
- oct = string.atoi (l[0]) - 4
- l= l[1:]
-
- while l[0] in ' \t':
- l= l[1:]
-
-
- print get_mudela_pitch (pitch,acc,oct), parse_duration(l[:2])
- l = l[2:]
-
-
-
-
-def parse_duration (l):
- s = ''
- while l[0] in '0123456789':
- s = s + l[0]
- l= l[1:]
- print l
- num = string.atoi (s)
- den = 4 * divisions
-
- current_dots = 0
- try_dots = [3, 2, 1]
- for d in try_dots:
- f = 1 << d
- multiplier = (2*f-1)
- if num % multiplier == 0 and den % f == 0:
- num = num / multiplier
- den = den / f
- current_dots = current_dots + d
-
- if num <> 1:
- sys.stderr.write ('huh. Durations left')
- return '%s%s' % (den, '.' * current_dots)
-
-comment_switch = 0
-for l in lines:
- if l[0] == '&':
- comment_switch = not comment_switch
- if comment_switch:
- l= l[1:]
- print '%{'
- else:
- print '%}'
-
- if comment_switch:
- print l
- continue
-
- if 0:
- pass
- elif l[0] == '$':
- print parse_musical_attributes (l)
- elif l[0] == '@':
- parse_line_comment (l)
-
- elif l[0] in 'ABCDEFG':
- parse_note_line (l)
{
\bigskip
{\flushright{\theopus}\par}
- {\flushleft{\large\normalfont\scshape\thepiece}}
+ {\flushleft{\large\normalfont\scshape\thepiece}\par}
\global\let\theopus\relax%
\global\let\thepiece\relax%
}