Skink is written in Java, and uses a parser written in Javacc. (so a c++ set of datastructures would have done me little good...) I actually started off with a C++ version using Flex++ and Bison, but found Java and never looked back... Some coments below, for what it's worth.
My strategy for
Paul Rosen wrote:
I found that parsing could be made fast enough that I can effectively re-parse the entire file and redisplayI've finally gotten a few free moments of time, and started thinking about the "universal parser" that we talked about a few months back. I started to write down the requirements for the output, which I've included below. I've included everything I could think of for formatting and playing music.
The idea here is to create a universal data structure suitable for all ABC applications. Then someone writing a better parser and someone writing a better formatter could work independently.
it on every keystroke. Very long files are not great, but moderate size files (~100 tunes) respond reasonably well
This is more-or-less what I did with Skink, though the intermediate representation is a set of objects,If you are interested in this, please comment on the following and tell me if I've left anything out or made incorrect assumptions. When I get a little more time, I'll create a C structure that can handle this and post that.
-----
ABC parser output data structure.
Goal
3. This is the data structure between the ABC parser and the application.
There are two main applications: a sheet music formatter, and music player.
I think other applications (like a transposer) would not have any unique
demands on the structure.
4. The goal is to have a flexible enough structure that additional
requirements would be handled without requiring fundamental changes to the
structure. With luck, some additional requirements may be handled without
any changes to the structure at all.
5. The purpose of this structure is to completely separate the parser, the
formatter, and the player. Each one of these three functions can be
developed independently, and different developers can have their pieces snap
in.
not a file. I have defined an interface for my renderer (I have two, for different versions of Java)
and for my player, (although I only have one at the moment.)
Not quite - there is additional content that is not inside any tune, and some of it might want to be displayed.General requirements
7. This structure is for a single tune. To do multiple tunes, you can simply have an array of these.
In particular, creating tables-of-contents, indexes, and pagenumbers needs some back-and-forth between
the tune and the display.
8. Everything possible should be interpreted as much as possible. In other words, a chord of "Gm" would be stored as a G minor chord, not the text "Gm". This allows the player to not need to do any parsing.
I'm not sure I agree with this - the chord notation has been much abused.
9. however, the original wording should be available if needed. In other words, "GM" and "G" are both a G major chord. Some formatting programs may wish to use one or the other exclusively, or may choose to parrot whatever was specified.
Yes...
10. Extra formatting information may be in the structure. The most obvious is the new staff indicator (the exclamation point) and the don't-connect-eighths indicator (the space). Room should be made for many others that may be put in the language later. For instance, what if the user wanted a measure to be spaced out more than the formatter naturally would? Or wanted to force the notes to be pointed up? Or wanted more room between two particular staffs? Or a new page? Or wanted to decide whether the last staff was justified or aligned to the left? In any case, no formatting is required, and in that case, the formatter makes all its own decisions.
OK
I think this restriction essentially ends up being true only for an intermediate form. For example, if you have11. The structure should have a simple, fixed format so that it can be saved to disk easily, or passed between programs written in different languages. The saved version would be something of a "compiled" version, that is, our equivalent of an OBJ file. This means that there can't be any pointers in the structure.
a | abcd | dead | cabb :| age
(a purposely "wrong", but often found construct) you will need to figure out how to point back to the
first barline for the repeat. In other words, the player will have to construct an intermediate form that
does have pointers.
12. A C++ class will encapsulate the structure, so that users of C++ can
easily gain access to the data in a natural way.
Java? Perl? Ruby? python? ...
General structure
14. There are two parts: 15. The header contains one-time only information. that includes the title, etc. It also contains global information, like whether to force all notes to be pointed up.
Voices will need to have this info.
You will need to define an 'extent' of notes that have certain characteristics. Some items will cause changes16. The body is an array of items. These items define a particular vertical space on the notation, and a particular time for the player. Note that the amount of space and amount of time is variable for each item. A simple example follows. Three possible items are a whole note, a half note, and a bar. each of the three takes a different amount of time to play (the bar takes no time to play). The bar takes a different amount of space to display than the notes.
in the player and/or the display context. For example
K:D |: abcd || [K:Bb] def abc :|
The first staff has two sharps, there is a change in key signature which changes the player context and the
second staff must have two flats. Then when your player repeats, it needs to be back to two sharps.
I'm not sure if you are advocating collapsing all voices into a single 'element'. That would make some things17. Items need to refer to neighboring (and farther off) items. For instance, an item may indicate that a slur has begun, and another item would indicate that it has ended.
Elements in the item
19. (All of the following are for a single stave. An element may also have multiple staves.)
easier, but it would make it perhaps more difficult to print separate voices on a separate sheet (since I have
yet to implement multi-voice, I guess I shouldn't be too picky..!)
Phil Taylor has done a great job in his 'stress programs' - specifying for a particular20. Multiple notes, each with a separate rhythm, and a voice number. 21. Chord symbol 22. Singing words (possibly multiple verses) 23. slurs and ties (connected to a particular note if multiple notes are present) 24. The greater and less than signs that show the differences in volume. 25. New key signature, new tempo, new time signature. 26. The following accents (multiple ones could be in each item, and sometimes multiple ones can be on each note in an item): slide up and down, muffled (note head is an X), diamond head note, loudness markings, fingering numbers, trill indicator, ritard, fermat, arpeggio, legato, staccato & pizzicato, bowing symbols, pedal on, pedal off, accent, attack, 27. This item is part of a set of grace notes (the rhythm for them should be stolen from the previous note.) 28. First ending, second ending, etc. 29. Bar line type: repeat, double, thick on left, etc. 30. Text in the staff instead of notes. That is: "8 bar intro", "piano solo", etc. 31. Non-chord note above the staff. for instance, to indicate a different instrument should start playing, or to label an interesting spot.
Elements in the header
33. All of the items in the header section of the ABC spec.
34. Additional verses. (probably printed at the bottom)
35. Global indicators, like number of staves and their clef.
36. Instrument name to the left of the staff.
37. Amount of swing (8th notes played dotted by how much)
rhythm how to adjust note length and volume.
One thing you might want to think about early is how to handle errors - Skink puts in its object
stream an 'error object' that refers to the place where the parser picked up the error, and then
recovers at the start of the next tune.
I'd strongly suggest using one of the parser builders out there - I was playing with PCCTS before
I jumped to Java, and I believer there are other compiler-compilers (including, of course, the
old stalwarts of lex (or flex++) and yacc (or bison).
Good luck!
wil
To subscribe/unsubscribe, point your browser to: http://www.tullochgorm.com/lists.html
Paul Rosen --- Life is a musical, every once in a while the plot stops and you start singing and dancing --- http://home.earthlink.net/~catharsis.music/ http://home.earthlink.net/~theplums/
To subscribe/unsubscribe, point your browser to: http://www.tullochgorm.com/lists.html