mirror of
https://github.com/sshlien/abcmidi.git
synced 2025-12-06 06:55:06 +00:00
135 lines
6.1 KiB
Plaintext
135 lines
6.1 KiB
Plaintext
Some Notes on the yaps Code
|
|
-------------------------------------------------------------
|
|
written by Seymour Shlien November 21 2004
|
|
|
|
This file gives an algorithmic description of the
|
|
yaps program which converts an abc file to a PostScript file.
|
|
|
|
The source consists of almost 10000 lines of C in the following
|
|
files.
|
|
|
|
parseabc.c is the front end which scans the abc file and invokes
|
|
the appropriate event handler for each element it encounters
|
|
(eg. bar lines, notes, chords etc.) It happens to be the
|
|
front end for other programs such as abc2midi, and
|
|
abc2abc. More details are given in abc2midi.txt.
|
|
|
|
yapstree.c contains all the event handlers called by the parser.
|
|
It produces a complex data structure called tune which
|
|
references many other structures. When the parser completes
|
|
processing the tune, event_blankline or event_eof calls
|
|
printtune (in drawtree.c) which processes the tune structure
|
|
producing a PostScript file. Unlike abc2midi, most of the
|
|
layout including the detailed beaming is done in the first
|
|
pass during the parsing stage. The information in this
|
|
structure is then processed by drawtune.c in two more
|
|
passes. An overview of these structures is provided here.
|
|
More details on the tune structure is provided in this
|
|
file.
|
|
|
|
drawtune.c contains the function printtune which turns the tune
|
|
structure into an actual PostScript file. This is done
|
|
in two passes. Before writing the PostScript file it
|
|
is necessary to determine the boundingbox of the output
|
|
image since this information is recorded in the header
|
|
of the output file. This is determined in the first pass
|
|
where functions monospace() or spacevoices() (in position.c)
|
|
are called. During this pass the pixel positions
|
|
of each object are recorded in the associated structures.
|
|
In the second pass, the actual PostScript file is written.
|
|
The function calls printlib() (in pslib.c) outputs
|
|
all the PostScript boiler plate macro definitions required
|
|
by yaps. The information in the tune structure is used
|
|
to output the music notation in a PostScript file.
|
|
|
|
|
|
position.c contains functions for determining the amount of space
|
|
that is required for the different music objects drawn
|
|
in the PostScript file.
|
|
|
|
parser2.c contains additional parsing functions missing in parseabc.
|
|
They handle more recent features added to the abcmidi package.
|
|
|
|
pslib.c Definition of new PostScript commands (eg. notes, clefs,
|
|
stems, tails, ...) which are copied to the PostScript
|
|
file.
|
|
|
|
debug.c Functions which support the -d option in yaps. It prints
|
|
some of the contents of the internal tune structure.
|
|
|
|
|
|
Data Structures
|
|
---------------
|
|
|
|
The data structures are defined in the include file structs.h.
|
|
|
|
The top level structure, tune is instantiated by init_tune which
|
|
is called by event_init or event_refno. It stores all the
|
|
information in the abc field commands (X: ,M:, L:, C:, O: and etc.).
|
|
It contains a pointer to the voice structure and a list of voice
|
|
pointers where most of the body information is recorded.
|
|
|
|
The voice structure is instantiated by the function newvoice
|
|
which is called by setvoice(n) whenever the voice context
|
|
switches in the abc file. Setvoice performs the voice switching
|
|
(which occurs in voice interleaved files) and either creates
|
|
a new voice or finds the matching voice structure already existing.
|
|
The voice structure contains the feature structure which
|
|
is somewhat similar in function to the one defined in store.c
|
|
(for abc2midi).
|
|
|
|
The feature structure encodes all the detailed information in
|
|
the body, using the same typedef enum featuretype defined
|
|
in abc.h. Unlike store.c there is no num and denom arrays. Instead
|
|
the feature struct contains a void* pointer called item which
|
|
can point to anything and where additional information can be
|
|
stored. If the feature type is a NOTE then a "note" struct
|
|
is created which records a lot of detailed information related
|
|
to the placement and visual representation of the note. They
|
|
include:
|
|
tail_type which specifies whether the note appears in
|
|
isolation or is part of a beamed group
|
|
base_exp whole, half, quarter, ... notes
|
|
dots how many dots follow
|
|
stemlength, stemup, fliphead, pitch, octave, accidentals, accents,...
|
|
(see struct.h)
|
|
Most of the information except actual positioning is determined
|
|
by functions such as count_dots and beamitem in yapstree.c.
|
|
You can view this information by running yaps.exe with the -d
|
|
run time parameter.
|
|
|
|
The handling of the note positioning is quite complex as
|
|
outlined below. It is therefore not easy to implement the
|
|
splitvoice feature into yaps. Here is a description.
|
|
|
|
The positioning of notes is done by the function
|
|
spacemultiline() which calls advance() unless one is printing
|
|
the voices separately. The positioning is done on all the voices
|
|
at the same time to ensure that they are lined up properly.
|
|
Spacemultiline accesses all the active voices using the functions
|
|
firstitem() and nextitem() which are used for handling any lists
|
|
of objects. Each voice maintains its own pointer to the current
|
|
feature being scanned (v->place). Each voice also maintains its
|
|
own pointer to the relative time of the note being scanned
|
|
in the variable v->time. (v->time contains both a numerator
|
|
and denominator.) The advance() function updates v->place,
|
|
v->time and interprets the voice features determining the
|
|
amount of space that is needed to plot the next object (itemspace)
|
|
and the number of plotable objects (items). The position to
|
|
plot the next object (x) is maintained by spacemultiline and
|
|
passed to advance. Advance() updates v->place->x with the position
|
|
to plot the object based on its width. Spacemultiline()
|
|
maintains a mastertime variable for maintaining synchrony
|
|
between all voices.
|
|
|
|
At least two passes are made through the voice features.
|
|
In the first pass provisional positions are computed for the
|
|
notes. The amount of space left over in the music lines is
|
|
computed and is used to determine the internote gaps.
|
|
In the second pass, the notes are repositioned to use up
|
|
the entire space in the staff line.
|
|
|
|
Spacemultiline is called for each staff line whose end is
|
|
signaled by a linefeed feature in the voice.
|
|
|