>We've been over this before, but back when BarFly was the only
>application to support both parts and multi-voice playback.  So
>maybe other implementations have moved on enough to merit a re-run.

In order to understand why BarFly won't do what you want I'll
have to explain how it works.

The program has two separate parsers for playing and display,
and they work quite differently from one another.

The play parser runs through the abc ignoring anything that
isn't required for playing (e.g. beams).  It generates a
list of midi codes and times, which can subsequently be
assembled into a Quicktime tune or a midi file or whatever.
It can't be started or stopped in mid-parse, but it can be
instructed not to generate output from some parts of the
tune, so you can do Play from Insertion Point or Play
Selection.  When playing multi-voice tunes it only parses
one voice at a time, seeking each V: field with the appropriate
voice number and skipping over the other voices.  It gets
called multiple times to assemble the complete tune for voice 1,
then voice 2 etc. until it has the whole thing.  When playing
a single voice tune with parts it also gets called multiple
times, once for each part in the order specified in the header.
In this case it parses the whole tune, but suppresses output
generated by abc outside of the requested part, and the output
is added at the end of the previous list to generate the
whole tune.  If it has to deal with both multivoice and parts
it deals first with voice 1, part A, then voice 1 part B etc.
until it has voice 1 complete, then goes on to voice 2 part A.

The reason why your example won't work:

>X:1
>T:Drink to me only.
>T:2 Flutes.
>M:6/8
>L:1/8
>Q:3/8=60
>P:ABA
>K:A
>P:A
>[V:1]   ccc d2d|(ed)c (Bc)d|(eA)d c2B   | HA6    :|
>[V:2]   AAA B2B|(cB)A (GA)B|(Ac)B A2[EG]|[HC6HA6]:|
>%
>P:B
>[V:1] e|ece a2e|(ec)e  e2e | f2e  d2c   | (c3 B2):|
>[V:2] c|cAc c2c|(cA)c  c2c | d2c  B2A   | (A3 G2):|

is that when parsing voice 1 part A, when it gets to the
end of the first line and encounters [V:2] it skips ahead to
find the next [V:1] field.  In doing so, it misses the P:B
field, since it is not contained within voice 1.  In fact,
the P:B field is contained only within voice 2, at the end
of the first line.

The display parser takes exactly two passes through the tune.
On the first pass it just determines where the line ends are,
and how many symbols are to be drawn on each line.  On the
second pass it draws each symbol to the screen.  If it's
single-voice abc there is no internal data structure to
represent the music.  If it's multi-voice then the output
is accumulated into a set of linked lists until it has a
complete block of staves, then the horizontal positions of
the symbols are adjusted to align them according to their
times, and the vertical positions of some symbols are adjusted
to avoid conflicts.  Each block is then drawn, and the data
structure is destroyed ready for the next block.  So the
display parser reads the complete tune from top to bottom
as a human would, and your part labels in the above example
work fine because both of them immediately precede the staff
where they are to be drawn.

The main reason why I did things the way I did was speed.
Nobody minds if they tell a computer to play and it takes
a second or two before the sound starts, but if you are
typing the abc and there's a second or two of dead time
after each keystroke you're not going to bother.  The
program was written to be used on a 25MHz Mac IIci, and
it's still usable on that machine.  The play parser was
written first, and at that time it didn't have to deal with
multivoice abc - that was a later modification.

Both parsers have their disadvantages.  As you've pointed
out, the positioning of part fields required to make them
play properly is too strict, and doesn't make sense unless
you know how the parser works.  Likewise, the display
parser can only deal with abc where the lines of abc are
entered in the order in which they are to be displayed.

However, fixing these problems will require a complete
re-write, and we're talking about half a million lines
of code here (Pascal is a verbose language).

Maybe when I get to version 2.0 I'll do it.  I'll write
a single parser which assembles the whole tune into a
data structure, with separate output routines to generate
midi or pictures of the staff notation.  It will be a lot
slower, but by that time even you will be using a machine
fast enough.

Phil Taylor


To subscribe/unsubscribe, point your browser to: http://www.tullochgorm.com/lists.html

Reply via email to