On 10 Sep 2004, at 05:32, Paul Rosen wrote:

as you might have read in other posts, I would be very interested in any
work on API for accessing ABC file once parsed. I still did not have a
clue
for creating one and I would welcome any suggestion! Just let me know when
you got an idea.

I would break the problem into two parts: first decide what data needs to be
represented, then figure out the physical layout.


Here's my first shot at a comprehensive description of the data:

Have a header section followed by a repeating field section.

The header section contains:
version - (probably either 1.6 or 2.0 or now)
tune number - int
title - arbitrary length string.
area - arbitrary length string.
book - arbitrary length string
composer - arbitrary length string.
discography - arbitrary length string.
elemskip - arbitrary length string.[What does this do?]

It's a hangover from abc2mtex. I don't think it's meaningful to any other program.


group - arbitrary length string.
history - arbitrary length string.
information - arbitrary length string.
notes - arbitrary length string.
origin - arbitrary length string.
source - arbitrary length string.
transcription notes - arbitrary length string.
rhythm - arbitrary length string.[can this be interpreted in any way?]

Yes. Several programs (BarFly, abcMus, abc2midi) use it to invoke a stress
program when playing. However, it's probably best to leave it as a string
here and let the controlling program interpret it.


default length - double?

Since the default length can have only a limited number of values an int or
enum would probably be more appropriate?


meter - double?

No. As you point out below you are going to want to deal with the distinction
between C and 4/4, and at some point deal with complex time signatures like 2+2+2+3/8.
In BarFly I opted for representing it as two integers, representing C and C| by
making the numerator negative, but it's a kludge and I have no sensible way of
extending it to deal with complex metres. It needs some serious thought.


tempo - [note length and beats per minute] double? and int
parts - array of bytes
starting key - enum

That enum's definition is going to be very large to deal with all possibilities.
It would probably be worth breaking this down into several fields, e.g.


tonic
mode
globalaccidentals
keysignature (an array of seven enums, each of which can represent #, b, natural or null?)


There's also some additional stuff which can go in the K: field:

middle
transpose
capo

[I'd suggest the following additional fields that aren't in the spec:
"clef", "copyright" and "additional lyrics"]

Then the header section is followed by a set of repeating fields of one of
three types.


The types are: note element, bar element, formatting element, and header
element.


the HEADER element is one of:
key (as above)
elemskip [What does this do?]
key (as above)
default length (as above)
meter (as above)
part - byte
tempo (as above)
title (as above)
words [how is this supposed to look?]

The BAR element contains:
bar type - enum (single, repeat left, etc.)
start ending - bit field
ending number - int
end ending - bit field

The FORMATTING element is one of:
End of line
break beam

The NOTE element contains:
guitar chord unrecognized - arbitrary length string
guitar chord recognized - root pitch (enum), type (enum), base note (enum)
gracings - enum
bowing - enum
staccato/legato - enum
one or more stacked notes, containing:
grace notes - array of pitches
pitch - enum [includes an enum for a rest]
length - int
start tie - bit field
end tie - bit field
start slur - bit field
end slur - bit field
[I'd also recommend the following extension: an array of syllables to appear
as the lyrics under the note.]
[Also, can we add "loudness", "fermat", and "start crescendo", "end
crescendo", "fingering", "retard", "a tempo", etc.?]


---

I think the above is fairly complete. Now, to represent it is tougher to
allow ease of use in all programming languages.


The way I'd represent it without using objects is with a stream of variable
length fields. That is, there would be a series of [type length data]
elements.


The overhead would be:
element type - enum
length - byte on some element types, short on some element types, and not
present for some element types.
data - length bytes of data, interpreted differently for each element type.


The beginning of the structure would contain a 2-byte version number and a
4-byte total length, and possibly a signature.


In addition, we could have an array of indexes into the start of each
element. Perhaps another array of indexes into the start of each "note"
element, so that a MIDI program wouldn't have to wade through non-sounding
elements.


The bit fields would be combined in a byte when possible.

The enums are a byte.

In the note structure, for each field there is a value that indicates that
the element isn't there. That is, one of the gracings is "none".


---

This is just a sketch. Obviously we would have to define it more carefully,
and define all our enums. I think the most important thing, first, is to
make sure that we can express anything we want with the structure. Also, we
should make sure that the structure is backward and forward compatible:
unknown fields should be easy to ignore.


I think the above can express anything in ABC, but I'd want to look toward
the future and try to express most things that can appear in music.


There is one major limitation with the data as expressed above: If the point
of the application using it is to modify the file, then comments, line
breaks, and other details are important so that the file looks as much like
the original as possible. In other words, not only should the structure be a
straightforward description of the music, it should have all the information
that is required to write the tune back out identically. For instance, we
should be able to tell between "C" and "4/4" in the time signature. One way
to handle comments, spaces, and line breaks is to have a second structure
that contained them and instructions for inserting them back where they need
to be. Many programs would ignore that, a transposing program wouldn't.


---

The other major problem is error reporting. We should recover if possible
from an error, but pass back information about where the error(s) occurred.


---

I suggest the following for indicating note length: Let's pick a small value
that is the shortest note length we support: perhaps a triplet of 1/64th
notes. That would be indicated by 1. Then internally every length is a
multiple of that.

I wouldn't use a tuplet length as your base value. Use a fractional power
of two (I think MusicXML uses 1/256) and deal with tuplets as they occur.



---

Now, the first thing that I would do is write a C++ class that accepts that
structure as input, and puts it into collections, with lots of access
functions. We could simulate that with C, where we write a set of functions
like:


GetNote(struct theData* pData, int iNoteNumber, struct aNote* pNote);

Personally, I'd rather work directly with the data, rather than use access
functions. It's possible that this would pose problems for some languages
though.


I wouldn't worry too much about overhead, since modern computers have vast
amounts of memory to play with. Much better to plan for the future (e.g.
by including blocks of unused space reserved for future use) than to strive
to keep it as compact as possible.

---

The thing that has always puzzled me about ABC is all the header fields. As
far as I can tell, not all programs treat the headers the same, and some
ignore some of them. Is there a recommended place that each of the header
text fields should go?

Apart from X: and K: they can go in any order. What I do in BarFly is rather than parsing the header from top to bottom I seek for the fields that I actually need, ignoring everything else.

Phil Taylor

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

Reply via email to